Ai小添加 (#320)
出牌策略仍然搞不定呀 - Qml: 新增leval函数可获得lua表达式的值 - 新增AbstractRoom类 去除冗余
This commit is contained in:
parent
7661cabd58
commit
c3cdb8dc50
|
@ -269,6 +269,15 @@ Window {
|
|||
}
|
||||
}
|
||||
|
||||
function leval(lua) {
|
||||
const ret = Backend.evalLuaExp(`return json.encode(${lua})`);
|
||||
try {
|
||||
return JSON.parse(ret);
|
||||
} catch (e) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
function luatr(src) {
|
||||
return Backend.translate(src);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
---@class Client
|
||||
---@class Client : AbstractRoom
|
||||
---@field public client fk.Client
|
||||
---@field public players ClientPlayer[] @ 所有参战玩家的数组
|
||||
---@field public alive_players ClientPlayer[] @ 所有存活玩家的数组
|
||||
---@field public observers ClientPlayer[] @ 观察者的数组
|
||||
---@field public current ClientPlayer @ 当前回合玩家
|
||||
---@field public discard_pile integer[] @ 弃牌堆
|
||||
---@field public status_skills Skill[] @ 状态技总和
|
||||
---@field public banners table<string, any> @ 左上角显示的东西
|
||||
---@field public observing boolean
|
||||
Client = class('Client')
|
||||
Client = AbstractRoom:subclass('Client')
|
||||
|
||||
-- load client classes
|
||||
ClientPlayer = require "client.clientplayer"
|
||||
|
@ -26,6 +24,7 @@ local pattern_refresh_commands = {
|
|||
}
|
||||
|
||||
function Client:initialize()
|
||||
AbstractRoom.initialize(self)
|
||||
self.client = fk.ClientInstance
|
||||
self.notifyUI = function(self, command, jsonData)
|
||||
fk.Backend:emitNotifyUI(command, jsonData)
|
||||
|
@ -49,21 +48,8 @@ function Client:initialize()
|
|||
end
|
||||
end
|
||||
|
||||
self.players = {} -- ClientPlayer[]
|
||||
self.alive_players = {}
|
||||
self.observers = {}
|
||||
self.discard_pile = {}
|
||||
self.status_skills = {}
|
||||
for class, skills in pairs(Fk.global_status_skill) do
|
||||
self.status_skills[class] = {table.unpack(skills)}
|
||||
end
|
||||
|
||||
self.banners = {}
|
||||
|
||||
self.skill_costs = {}
|
||||
self.card_marks = {}
|
||||
self.filtered_cards = {}
|
||||
self.printed_cards = {}
|
||||
self.disabled_packs = {}
|
||||
self.disabled_generals = {}
|
||||
|
||||
|
@ -71,7 +57,7 @@ function Client:initialize()
|
|||
end
|
||||
|
||||
---@param id integer
|
||||
---@return ClientPlayer
|
||||
---@return ClientPlayer?
|
||||
function Client:getPlayerById(id)
|
||||
if id == Self.id then return Self end
|
||||
for _, p in ipairs(self.players) do
|
||||
|
@ -237,15 +223,6 @@ function Client:setCardNote(ids, msg)
|
|||
end
|
||||
end
|
||||
|
||||
function Client:setBanner(name, value)
|
||||
if value == 0 then value = nil end
|
||||
self.banners[name] = value
|
||||
end
|
||||
|
||||
function Client:getBanner(name)
|
||||
return self.banners[name]
|
||||
end
|
||||
|
||||
fk.client_callback["SetCardFootnote"] = function(jsonData)
|
||||
local data = json.decode(jsonData)
|
||||
ClientInstance:setCardNote(data[1], data[2]);
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
-- 作Room和Client的基类,这二者有不少共通之处
|
||||
---@class AbstractRoom : Object
|
||||
---@fiele public players Player[] @ 房内参战角色们
|
||||
---@field public alive_players Player[] @ 所有存活玩家的数组
|
||||
---@field public observers Player[] @ 看戏的
|
||||
---@field public current Player @ 当前行动者
|
||||
---@field public status_skills table<class, Skill[]> @ 这个房间中含有的状态技列表
|
||||
---@field public filtered_cards table<integer, Card> @ 见于Engine,其实在这
|
||||
---@field public printed_cards table<integer, Card> @ 同上
|
||||
---@field public skill_costs table<string, any> @ 用来存skill.cost_data
|
||||
---@field public card_marks table<integer, any> @ 用来存实体卡的card.mark
|
||||
---@field public banners table<string, any> @ 全局mark
|
||||
local AbstractRoom = class("AbstractRoom")
|
||||
|
||||
function AbstractRoom:initialize()
|
||||
self.players = {}
|
||||
self.alive_players = {}
|
||||
self.observers = {}
|
||||
self.current = nil
|
||||
|
||||
self.status_skills = {}
|
||||
for class, skills in pairs(Fk.global_status_skill) do
|
||||
self.status_skills[class] = {table.unpack(skills)}
|
||||
end
|
||||
|
||||
self.filtered_cards = {}
|
||||
self.printed_cards = {}
|
||||
self.skill_costs = {}
|
||||
self.card_marks = {}
|
||||
self.banners = {}
|
||||
end
|
||||
|
||||
-- 仅供注释,其余空函数一样
|
||||
---@param id integer
|
||||
---@return Player?
|
||||
function AbstractRoom:getPlayerById(id) end
|
||||
|
||||
--- 获取一张牌所处的区域。
|
||||
---@param cardId integer | Card @ 要获得区域的那张牌,可以是Card或者一个id
|
||||
---@return CardArea @ 这张牌的区域
|
||||
function AbstractRoom:getCardArea(cardId) end
|
||||
|
||||
function AbstractRoom:setBanner(name, value)
|
||||
if value == 0 then value = nil end
|
||||
self.banners[name] = value
|
||||
end
|
||||
|
||||
function AbstractRoom:getBanner(name)
|
||||
return self.banners[name]
|
||||
end
|
||||
|
||||
return AbstractRoom
|
|
@ -78,20 +78,20 @@ function Engine:initialize()
|
|||
end
|
||||
|
||||
local _foreign_keys = {
|
||||
"currentResponsePattern",
|
||||
"currentResponseReason",
|
||||
"filtered_cards",
|
||||
"printed_cards",
|
||||
["currentResponsePattern"] = true,
|
||||
["currentResponseReason"] = true,
|
||||
["filtered_cards"] = true,
|
||||
["printed_cards"] = true,
|
||||
}
|
||||
|
||||
function Engine:__index(k)
|
||||
if table.contains(_foreign_keys, k) then
|
||||
if _foreign_keys[k] then
|
||||
return self:currentRoom()[k]
|
||||
end
|
||||
end
|
||||
|
||||
function Engine:__newindex(k, v)
|
||||
if table.contains(_foreign_keys, k) then
|
||||
if _foreign_keys[k] then
|
||||
self:currentRoom()[k] = v
|
||||
else
|
||||
rawset(self, k, v)
|
||||
|
@ -548,7 +548,7 @@ function Engine:_addPrintedCard(card)
|
|||
end
|
||||
|
||||
--- 获知当前的Engine是跑在服务端还是客户端,并返回相应的实例。
|
||||
---@return Room | Client
|
||||
---@return AbstractRoom
|
||||
function Engine:currentRoom()
|
||||
if RoomInstance then
|
||||
return RoomInstance
|
||||
|
|
|
@ -33,6 +33,7 @@ UsableSkill = require "core.skill_type.usable_skill"
|
|||
StatusSkill = require "core.skill_type.status_skill"
|
||||
Player = require "core.player"
|
||||
GameMode = require "core.game_mode"
|
||||
AbstractRoom = require "core.abstract_room"
|
||||
UI = require "ui-util"
|
||||
|
||||
-- 读取配置文件。
|
||||
|
|
|
@ -132,9 +132,24 @@ end
|
|||
-- 真的要考虑ViewAsSkill吗,害怕
|
||||
---------------------------------------------------------
|
||||
|
||||
-- 使用牌相关——同时见于主动使用和响应式使用。
|
||||
--- 键是prompt的第一项或者牌名,优先prompt,其次name,实在不行trueName。
|
||||
---@type table<string, fun(self: SmartAI, pattern: string, prompt: string, cancelable?: boolean, extra_data?: UseExtraData): UseReply?>
|
||||
fk.ai_use_card = {}
|
||||
fk.ai_use_card = setmetatable({}, {
|
||||
__index = function(_, k)
|
||||
-- FIXME: 感觉不妥
|
||||
local c = Fk.all_card_types[k]
|
||||
if not c then return nil end
|
||||
if c.type == Card.TypeEquip then
|
||||
return function(self, pattern, prompt, cancelable, extra_data)
|
||||
local slashes = self:getCards(k, "use", extra_data)
|
||||
if #slashes == 0 then return nil end
|
||||
|
||||
return self:buildUseReply(slashes[1].id)
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
local defauld_use_card = function(self, pattern, _, cancelable, exdata)
|
||||
if cancelable then return nil end
|
||||
|
@ -219,6 +234,9 @@ smart_cb["PlayCard"] = function(self)
|
|||
local card_names = {}
|
||||
for _, cd in ipairs(cards) do
|
||||
-- TODO: 视为技
|
||||
-- 视为技对应的function一般会返回一张印出来的卡,又要纳入新的考虑范围了
|
||||
-- 不过这种根据牌名判断的逻辑而言 可能需要调用多次视为技函数了
|
||||
-- 要用好空间换时间
|
||||
table.insertIfNeed(card_names, cd.name)
|
||||
end
|
||||
-- TODO: 主动技
|
||||
|
@ -277,7 +295,7 @@ function SmartAI:isFriend(target)
|
|||
if Self.role == target.role then return true end
|
||||
local t = { "lord", "loyalist" }
|
||||
if table.contains(t, Self.role) and table.contains(t, target.role) then return true end
|
||||
if Self.role == "renegade" or target.role == "renegade" then return math.random() < 0.5 end
|
||||
if Self.role == "renegade" or target.role == "renegade" then return math.random() < 0.6 end
|
||||
return false
|
||||
end
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
--- Room是fk游戏逻辑运行的主要场所,同时也提供了许多API函数供编写技能使用。
|
||||
---
|
||||
--- 一个房间中只有一个Room实例,保存在RoomInstance全局变量中。
|
||||
---@class Room : Object
|
||||
---@class Room : AbstractRoom
|
||||
---@field public room fk.Room @ C++层面的Room类实例,别管他就是了,用不着
|
||||
---@field public id integer @ 房间的id
|
||||
---@field private main_co any @ 本房间的主协程
|
||||
|
@ -15,7 +15,6 @@
|
|||
---@field public game_finished boolean @ 游戏是否已经结束
|
||||
---@field public timeout integer @ 出牌时长上限
|
||||
---@field public tag table<string, any> @ Tag清单,其实跟Player的标记是差不多的东西
|
||||
---@field public banners table<string, any> @ 左上角显示点啥好呢?
|
||||
---@field public general_pile string[] @ 武将牌堆,这是可用武将名的数组
|
||||
---@field public draw_pile integer[] @ 摸牌堆,这是卡牌id的数组
|
||||
---@field public discard_pile integer[] @ 弃牌堆,也是卡牌id的数组
|
||||
|
@ -23,14 +22,13 @@
|
|||
---@field public void integer[] @ 从游戏中除外区,一样的是卡牌id数组
|
||||
---@field public card_place table<integer, CardArea> @ 每个卡牌的id对应的区域,一张表
|
||||
---@field public owner_map table<integer, integer> @ 每个卡牌id对应的主人,表的值是那个玩家的id,可能是nil
|
||||
---@field public status_skills Skill[] @ 这个房间中含有的状态技列表
|
||||
---@field public settings table @ 房间的额外设置,差不多是json对象
|
||||
---@field public logic GameLogic @ 这个房间使用的游戏逻辑,可能根据游戏模式而变动
|
||||
---@field public request_queue table<userdata, table>
|
||||
---@field public request_self table<integer, integer>
|
||||
---@field public skill_costs table<string, any> @ 存放skill.cost_data用
|
||||
---@field public card_marks table<integer, any> @ 存放card.mark之用
|
||||
local Room = class("Room")
|
||||
local Room = AbstractRoom:subclass("Room")
|
||||
|
||||
-- load classes used by the game
|
||||
GameEvent = require "server.gameevent"
|
||||
|
@ -67,18 +65,14 @@ dofile "lua/server/ai/init.lua"
|
|||
--- 构造函数。别去构造
|
||||
---@param _room fk.Room
|
||||
function Room:initialize(_room)
|
||||
AbstractRoom.initialize(self)
|
||||
self.room = _room
|
||||
self.id = _room:getId()
|
||||
|
||||
self.players = {}
|
||||
self.alive_players = {}
|
||||
self.observers = {}
|
||||
self.current = nil
|
||||
self.game_started = false
|
||||
self.game_finished = false
|
||||
self.timeout = _room:getTimeout()
|
||||
self.tag = {}
|
||||
self.banners = {}
|
||||
self.general_pile = {}
|
||||
self.draw_pile = {}
|
||||
self.discard_pile = {}
|
||||
|
@ -86,16 +80,8 @@ function Room:initialize(_room)
|
|||
self.void = {}
|
||||
self.card_place = {}
|
||||
self.owner_map = {}
|
||||
self.status_skills = {}
|
||||
for class, skills in pairs(Fk.global_status_skill) do
|
||||
self.status_skills[class] = {table.unpack(skills)}
|
||||
end
|
||||
self.request_queue = {}
|
||||
self.request_self = {}
|
||||
self.skill_costs = {}
|
||||
self.card_marks = {}
|
||||
self.filtered_cards = {}
|
||||
self.printed_cards = {}
|
||||
|
||||
self.settings = json.decode(self.room:settings())
|
||||
self.disabled_packs = self.settings.disabledPack
|
||||
|
@ -568,15 +554,10 @@ function Room:removeTag(tag_name)
|
|||
end
|
||||
|
||||
function Room:setBanner(name, value)
|
||||
if value == 0 then value = nil end
|
||||
self.banners[name] = value
|
||||
AbstractRoom.setBanner(self, name, value)
|
||||
self:doBroadcastNotify("SetBanner", json.encode{ name, value })
|
||||
end
|
||||
|
||||
function Room:getBanner(name)
|
||||
return self.banners[name]
|
||||
end
|
||||
|
||||
---@return boolean
|
||||
local function execGameEvent(type, ...)
|
||||
local event = GameEvent:new(type, ...)
|
||||
|
|
|
@ -1,266 +1,80 @@
|
|||
require "packages.standard.ai.aux_skills"
|
||||
|
||||
--[[
|
||||
fk.ai_use_play["rende"] = function(self, skill)
|
||||
for _, p in ipairs(self.friends_noself) do
|
||||
if p.kingdom == "shu" and #self.player:getCardIds("h") >= self.player.hp then
|
||||
self.use_id = {}
|
||||
for _, cid in ipairs(self.player:getCardIds("h")) do
|
||||
if #self.use_id < #self.player:getCardIds("h") / 2 then
|
||||
table.insert(self.use_id, cid)
|
||||
end
|
||||
end
|
||||
self.use_tos = { p.id }
|
||||
return
|
||||
end
|
||||
end
|
||||
for _, p in ipairs(self.friends_noself) do
|
||||
if #self.player:getCardIds("h") >= self.player.hp then
|
||||
self.use_id = {}
|
||||
for _, cid in ipairs(self.player:getCardIds("h")) do
|
||||
if #self.use_id < #self.player:getCardIds("h") / 2 then
|
||||
table.insert(self.use_id, cid)
|
||||
end
|
||||
end
|
||||
self.use_tos = { p.id }
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_card["jijiang"] = { priority = 10 }
|
||||
|
||||
fk.ai_use_play["lijian"] = function(self, skill)
|
||||
local c = Fk:cloneCard("duel")
|
||||
c.skillName = "lijian"
|
||||
local cards = table.map(
|
||||
self.player:getCardIds("he"),
|
||||
function(id)
|
||||
return Fk:getCardById(id)
|
||||
end
|
||||
)
|
||||
self:sortValue(cards)
|
||||
for _, p in ipairs(self.enemies) do
|
||||
for _, pt in ipairs(self.enemies) do
|
||||
if p.gender == General.Male and pt.gender == General.Male and p.id ~= pt.id
|
||||
and c.skill:targetFilter(pt.id, {}, p.id, c) then
|
||||
self.use_id = { cards[1].id }
|
||||
self.use_tos = { pt.id, p.id }
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, p in ipairs(self.friends_noself) do
|
||||
for _, pt in ipairs(self.enemies) do
|
||||
if p.gender == General.Male and pt.gender == General.Male and p.id ~= pt.id
|
||||
and c.skill:targetFilter(pt.id, {}, p.id, c) then
|
||||
self.use_id = { cards[1].id }
|
||||
self.use_tos = { pt.id, p.id }
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_card["lijian"] = { priority = 2 }
|
||||
|
||||
fk.ai_use_play["zhiheng"] = function(self, skill)
|
||||
local card_ids = {}
|
||||
local cards = table.map(
|
||||
self.player:getCardIds("he"),
|
||||
function(id)
|
||||
return Fk:getCardById(id)
|
||||
end
|
||||
)
|
||||
self:sortValue(cards)
|
||||
for _, h in ipairs(cards) do
|
||||
if #card_ids < #cards / 2 then
|
||||
table.insert(card_ids, h.id)
|
||||
end
|
||||
end
|
||||
if #card_ids > 0 then
|
||||
self.use_id = card_ids
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_use_play["kurou"] = function(self, skill)
|
||||
if #self:getActives("peach") + self.player.hp > 1 then
|
||||
local slash = Fk:cloneCard("slash")
|
||||
if slash.skill:canUse(self.player, slash) and not self.player:prohibitUse(slash) then
|
||||
fk.ai_use_play.slash(self, slash)
|
||||
if self.use_id then
|
||||
self.use_id = {}
|
||||
self.use_tos = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_use_play["fanjian"] = function(self, skill)
|
||||
for _, p in ipairs(self.enemies) do
|
||||
if #self.player:getCardIds("h") > 0 then
|
||||
self.use_id = {}
|
||||
table.insert(self.use_tos, p.id)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_use_play["jieyin"] = function(self, skill)
|
||||
local cards = table.map(
|
||||
self.player:getCardIds("h"),
|
||||
function(id)
|
||||
return Fk:getCardById(id)
|
||||
end
|
||||
)
|
||||
self:sortValue(cards)
|
||||
for _, p in ipairs(self.friends_noself) do
|
||||
if #cards > 1 and p.gender == General.Male and p:isWounded() then
|
||||
self.use_id = { cards[1].id, cards[2].id }
|
||||
table.insert(self.use_tos, p.id)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_use_play["qingnang"] = function(self, skill)
|
||||
local cards = table.map(
|
||||
self.player:getCardIds("h"),
|
||||
function(id)
|
||||
return Fk:getCardById(id)
|
||||
end
|
||||
)
|
||||
self:sortValue(cards)
|
||||
for _, p in ipairs(self.friends) do
|
||||
if #cards > 0 and p:isWounded() then
|
||||
self.use_id = { cards[1].id }
|
||||
table.insert(self.use_tos, p.id)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
-- 魏国
|
||||
|
||||
fk.ai_skill_invoke["jianxiong"] = true
|
||||
-- TODO: hujia
|
||||
-- TODO: guicai 关于如何界定判定的好坏 需要向AI中单独说明
|
||||
|
||||
fk.ai_card["hujia"] = { priority = 10 }
|
||||
fk.ai_skill_invoke["fankui"] = function(self)
|
||||
local room = self.room
|
||||
local logic = room.logic
|
||||
|
||||
fk.ai_response_card["#hujia-ask"] = function(self, pattern, prompt, cancelable, data)
|
||||
local to = self.room:getPlayerById(tonumber(prompt:split(":")[2]))
|
||||
if to and self:isFriend(to) and (self:isWeak(to) or #self:getActives(pattern)>1) then
|
||||
self:setUseId(pattern)
|
||||
end
|
||||
-- 询问反馈时,处于on_cost环节,当前事件必是damage且有from
|
||||
local event = logic:getCurrentEvent()
|
||||
local dmg = event.data[1]
|
||||
return self:isEnemy(dmg.from)
|
||||
end
|
||||
|
||||
fk.ai_response_card["#jijiang-ask"] = fk.ai_response_card["#hujia-ask"]
|
||||
fk.ai_skill_invoke["ganglie"] = fk.ai_skill_invoke["fankui"]
|
||||
|
||||
fk.ai_skill_invoke["fankui"] = function(self, data, prompt)
|
||||
local damage = self:eventData("Damage")
|
||||
return damage and damage.from and not self:isFriend(damage.from)
|
||||
end
|
||||
-- TODO: tuxi
|
||||
|
||||
fk.ai_response_card["#guicai-ask"] = function(self, pattern, prompt, cancelable, data)
|
||||
local cards = table.map(self.player:getHandlyIds(true), function(id)
|
||||
return Fk:getCardById(id)
|
||||
end)
|
||||
local id = self:getRetrialCardId(cards)
|
||||
if id then
|
||||
self.use_id = id
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_skill_invoke["ganglie"] = function(self, data, prompt)
|
||||
local damage = self:eventData("Damage")
|
||||
return damage and damage.from and not self:isFriend(damage.from)
|
||||
end
|
||||
|
||||
fk.ai_judge["ganglie"] = { ".|.|heart", false }
|
||||
|
||||
fk.ai_skill_invoke["luoyi"] = function(self, data, prompt)
|
||||
for _, p in ipairs(self.enemies) do
|
||||
if #self:getActives("slash") > 0 and not self:isWeak() then
|
||||
return true
|
||||
end
|
||||
end
|
||||
fk.ai_skill_invoke["luoyi"] = function(self)
|
||||
return false
|
||||
end
|
||||
|
||||
fk.ai_skill_invoke["tiandu"] = true
|
||||
|
||||
fk.ai_skill_invoke["yiji"] = true
|
||||
-- TODO: yiji
|
||||
|
||||
fk.ai_skill_invoke["luoshen"] = true
|
||||
|
||||
fk.ai_skill_invoke["guanxing"] = true
|
||||
-- TODO: qingguo
|
||||
|
||||
fk.ai_skill_invoke["tieqi"] = function(self, data, prompt)
|
||||
local use = self:eventData("UseCard")
|
||||
for _, p in ipairs(TargetGroup:getRealTargets(use.tos)) do
|
||||
p = self.room:getPlayerById(p)
|
||||
if self:isEnemy(p) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
-- 蜀国
|
||||
-- TODO: rende
|
||||
-- TODO: jijiang
|
||||
-- TODO: wusheng
|
||||
-- TODO: guanxing
|
||||
-- TODO: longdan
|
||||
|
||||
fk.ai_skill_invoke["tieqi"] = function(self)
|
||||
local room = self.room
|
||||
local logic = room.logic
|
||||
|
||||
-- 询问反馈时,处于on_cost环节,当前事件必是damage且有from
|
||||
local event = logic:getCurrentEvent()
|
||||
local use = event.data[1] ---@type CardUseStruct
|
||||
return table.find(use.tos, function(t)
|
||||
return self:isEnemy(room:getPlayerById(t[1]))
|
||||
end)
|
||||
end
|
||||
|
||||
fk.ai_skill_invoke["jizhi"] = true
|
||||
|
||||
-- 吴国
|
||||
-- TODO: zhiheng
|
||||
-- TODO: qixi
|
||||
|
||||
fk.ai_skill_invoke["keji"] = true
|
||||
|
||||
-- TODO: kurou
|
||||
|
||||
fk.ai_skill_invoke["yingzi"] = true
|
||||
|
||||
fk.ai_skill_invoke["lianying"] = true
|
||||
-- TODO: fanjian
|
||||
-- TODO: guose
|
||||
-- TODO: liuli
|
||||
|
||||
fk.ai_skill_invoke["lianying"] = true
|
||||
fk.ai_skill_invoke["xiaoji"] = true
|
||||
|
||||
-- TODO: jieyin
|
||||
|
||||
-- 群雄
|
||||
-- TODO: qingnang
|
||||
-- TODO: jijiu
|
||||
-- TODO: wushuang
|
||||
-- TODO: lijian
|
||||
fk.ai_skill_invoke["biyue"] = true
|
||||
|
||||
fk.ai_choose_players["tuxi"] = function(self, targets, min_num, num, cancelable)
|
||||
for _, pid in ipairs(targets) do
|
||||
local p = self.room:getPlayerById(pid)
|
||||
if self:isEnemy(p) and #self.use_tos < num then
|
||||
table.insert(self.use_tos, pid)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_active_skill["yiji_active"] = function(self, prompt, cancelable, data)
|
||||
for _, p in ipairs(self.friends_noself) do
|
||||
for c, cid in ipairs(self.player.tag["yiji_ids"]) do
|
||||
c = Fk:getCardById(cid)
|
||||
if c:getMark("yiji") > 0 and c.skill:canUse(p, c) then
|
||||
self.use_tos = { p.id }
|
||||
self.use_id = json.encode {
|
||||
skill = "yiji_active",
|
||||
subcards = { cid }
|
||||
}
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_choose_players["liuli"] = function(self, targets, min_num, num, cancelable)
|
||||
local cards = table.map(
|
||||
self.player:getCardIds("he"),
|
||||
function(id)
|
||||
return Fk:getCardById(id)
|
||||
end
|
||||
)
|
||||
self:sortValue(cards)
|
||||
for _, pid in ipairs(targets) do
|
||||
local p = self.room:getPlayerById(pid)
|
||||
if self:isEnemy(p) and #self.use_tos < num and #cards > 0 then
|
||||
table.insert(self.use_tos, pid)
|
||||
self.use_id = { cards[1].id }
|
||||
return
|
||||
end
|
||||
end
|
||||
for _, pid in ipairs(targets) do
|
||||
local p = self.room:getPlayerById(pid)
|
||||
if not self:isFriend(p) and #self.use_tos < num and #cards > 0 then
|
||||
table.insert(self.use_tos, pid)
|
||||
self.use_id = { cards[1].id }
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
--]]
|
||||
|
|
|
@ -1,16 +1,50 @@
|
|||
-- TODO: 合法性的方便函数
|
||||
-- TODO: 关于如何选择多个目标
|
||||
-- TODO: 关于装备牌
|
||||
|
||||
-- 基本牌:杀,闪,桃
|
||||
|
||||
fk.ai_use_card["slash"] = function(self, pattern, prompt, cancelable, extra_data)
|
||||
local slashes = self:getCards("slash", "use", extra_data)
|
||||
---@param from ServerPlayer
|
||||
---@param to ServerPlayer
|
||||
---@param card Card
|
||||
local function tgtValidator(from, to, card)
|
||||
return not from:prohibitUse(card) and
|
||||
not from:isProhibited(to, card) and
|
||||
true -- feasible
|
||||
end
|
||||
|
||||
local function justUse(self, card_name, extra_data)
|
||||
local slashes = self:getCards(card_name, "use", extra_data)
|
||||
if #slashes == 0 then return nil end
|
||||
|
||||
return self:buildUseReply(slashes[1].id)
|
||||
end
|
||||
|
||||
---@param self SmartAI
|
||||
---@param card_name string
|
||||
local function useToEnemy(self, card_name, extra_data)
|
||||
local slashes = self:getCards(card_name, "use", extra_data)
|
||||
if #slashes == 0 then return nil end
|
||||
|
||||
-- TODO: 目标合法性
|
||||
local targets = {}
|
||||
if self.enemies[1] then table.insert(targets, self.enemies[1].id) end
|
||||
if self.enemies[1] then
|
||||
table.insert(targets, self.enemies[1].id)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
return self:buildUseReply(slashes[1].id, targets)
|
||||
end
|
||||
|
||||
fk.ai_use_card["slash"] = function(self, pattern, prompt, cancelable, extra_data)
|
||||
return useToEnemy(self, "slash", extra_data)
|
||||
end
|
||||
|
||||
fk.ai_use_card["jink"] = function(self, pattern, prompt, cancelable, extra_data)
|
||||
return justUse(self, "jink", extra_data)
|
||||
end
|
||||
|
||||
fk.ai_use_card["peach"] = function(self, _, _, _, extra_data)
|
||||
local cards = self:getCards("peach", "use", extra_data)
|
||||
if #cards == 0 then return nil end
|
||||
|
@ -32,443 +66,22 @@ fk.ai_use_card["#AskForPeaches"] = function(self)
|
|||
return nil
|
||||
end
|
||||
|
||||
--[[
|
||||
fk.ai_card.slash = {
|
||||
intention = 100, -- 身份值
|
||||
value = 4, -- 卡牌价值
|
||||
priority = 2.5 -- 使用优先值
|
||||
}
|
||||
fk.ai_card.peach = {
|
||||
intention = -150,
|
||||
value = 10,
|
||||
priority = 0.5
|
||||
}
|
||||
fk.ai_card.dismantlement = {
|
||||
intention = function(self, card, from)
|
||||
if #self.player.player_cards[Player.Judge] < 1 then
|
||||
return 80
|
||||
elseif self.ai_role[from.id] == "neutral" then
|
||||
return 30
|
||||
end
|
||||
end,
|
||||
value = 3.5,
|
||||
priority = 10.5
|
||||
}
|
||||
fk.ai_card.snatch = {
|
||||
intention = function(self, card, from)
|
||||
if #self.player.player_cards[Player.Judge] < 1 then
|
||||
return 80
|
||||
elseif self.ai_role[from.id] == "neutral" then
|
||||
return 30
|
||||
end
|
||||
end,
|
||||
value = 4.5,
|
||||
priority = 10.4
|
||||
}
|
||||
fk.ai_card.duel = {
|
||||
intention = 120,
|
||||
value = 4.5,
|
||||
priority = 3.5
|
||||
}
|
||||
fk.ai_card.collateral = {
|
||||
intention = 20,
|
||||
value = 3,
|
||||
priority = 4.5
|
||||
}
|
||||
fk.ai_card.ex_nihilo = {
|
||||
intention = -200,
|
||||
value = 8,
|
||||
priority = 10
|
||||
}
|
||||
fk.ai_card.savage_assault = {
|
||||
intention = 20,
|
||||
value = 2,
|
||||
priority = 4
|
||||
}
|
||||
fk.ai_card.archery_attack = {
|
||||
intention = 30,
|
||||
value = 2,
|
||||
priority = 3
|
||||
}
|
||||
fk.ai_card.god_salvation = {
|
||||
intention = function(self, card, from)
|
||||
if self.player.hp ~= self.player.maxHp then
|
||||
return -45
|
||||
end
|
||||
end,
|
||||
value = 1.5,
|
||||
priority = 4
|
||||
}
|
||||
fk.ai_card.amazing_grace = {
|
||||
intention = -30,
|
||||
value = 2,
|
||||
priority = 2
|
||||
}
|
||||
fk.ai_card.indulgence = {
|
||||
intention = 150,
|
||||
value = -1,
|
||||
priority = 2
|
||||
}
|
||||
|
||||
local function slashEeffect(slash, to)
|
||||
for _, s in ipairs(to:getAllSkills()) do
|
||||
if s.name == "#vine_skill" then
|
||||
if slash.name == "slash" then
|
||||
return
|
||||
end
|
||||
end
|
||||
if s.name == "#nioh_shield_skill" then
|
||||
if slash.color == Card.Black then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
fk.ai_use_card["dismantlement"] = function(self, pattern, prompt, cancelable, extra_data)
|
||||
return useToEnemy(self, "dismantlement", extra_data)
|
||||
end
|
||||
|
||||
fk.ai_use_play["slash"] = function(self, card)
|
||||
self:sort(self.enemies)
|
||||
for _, p in ipairs(self.enemies) do
|
||||
if card.skill:targetFilter(p.id, self.use_tos, {}, card) and slashEeffect(card, p) and self:objectiveLevel(p) > 2 then
|
||||
self.use_id = card.id
|
||||
table.insert(self.use_tos, p.id)
|
||||
end
|
||||
end
|
||||
fk.ai_use_card["snatch"] = function(self, pattern, prompt, cancelable, extra_data)
|
||||
return useToEnemy(self, "snatch", extra_data)
|
||||
end
|
||||
|
||||
fk.ai_use_card["#slash-jink"] = function(self, pattern, prompt, cancelable, extra_data)
|
||||
local act = self:getActives(pattern)
|
||||
if tonumber(prompt:split(":")[4]) > #act then
|
||||
return
|
||||
end
|
||||
local cards =
|
||||
table.map(
|
||||
self.player:getCardIds("&he"),
|
||||
function(id)
|
||||
return Fk:getCardById(id)
|
||||
end
|
||||
)
|
||||
self:sortValue(cards)
|
||||
for _, sth in ipairs(act) do
|
||||
if sth:isInstanceOf(Card) then
|
||||
self.use_id = sth.id
|
||||
break
|
||||
else
|
||||
local selected = {}
|
||||
for _, c in ipairs(cards) do
|
||||
if sth.cardFilter(sth, c.id, selected) then
|
||||
table.insert(selected, c.id)
|
||||
end
|
||||
end
|
||||
local tc = sth.viewAs(sth, selected)
|
||||
if tc and tc:matchPattern(pattern) then
|
||||
self.use_id =
|
||||
json.encode {
|
||||
skill = sth.name,
|
||||
subcards = selected
|
||||
}
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
fk.ai_use_card["duel"] = function(self, pattern, prompt, cancelable, extra_data)
|
||||
return useToEnemy(self, "duel", extra_data)
|
||||
end
|
||||
|
||||
fk.ai_use_card["#slash-jinks"] = fk.ai_use_card["#slash-jink"]
|
||||
|
||||
fk.ai_use_play["snatch"] = function(self, card)
|
||||
for _, p in ipairs(self.friends_noself) do
|
||||
if card.skill:targetFilter(p.id, self.use_tos, {}, card) and #p:getCardIds("j") > 0 then
|
||||
self.use_id = card.id
|
||||
table.insert(self.use_tos, p.id)
|
||||
end
|
||||
end
|
||||
self:sort(self.enemies)
|
||||
for _, p in ipairs(self.enemies) do
|
||||
if card.skill:targetFilter(p.id, self.use_tos, {}, card) and #p:getCardIds("he") > 0 then
|
||||
self.use_id = card.id
|
||||
table.insert(self.use_tos, p.id)
|
||||
end
|
||||
end
|
||||
fk.ai_use_card["ex_nihilo"] = function(self, pattern, prompt, cancelable, extra_data)
|
||||
return justUse(self, "ex_nihilo", extra_data)
|
||||
end
|
||||
|
||||
fk.ai_nullification.snatch = function(self, card, to, from, positive)
|
||||
if positive then
|
||||
if self:isFriend(to) and not self:isFriend(from) and self.ai_role[from.id] ~= "neutral" then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) or to.id == self.player.id then
|
||||
self.use_id = self.avail_cards[1]
|
||||
fk.ai_use_card["indulgence"] = function(self, pattern, prompt, cancelable, extra_data)
|
||||
return useToEnemy(self, "indulgence", extra_data)
|
||||
end
|
||||
end
|
||||
else
|
||||
if self:isEnemy(to) and self:isEnemy(from) then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) then
|
||||
self.use_id = self.avail_cards[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_use_play["dismantlement"] = function(self, card)
|
||||
for _, p in ipairs(self.friends_noself) do
|
||||
if card.skill:targetFilter(p.id, self.use_tos, {}, card) and #p:getCardIds("j") > 0 then
|
||||
self.use_id = card.id
|
||||
table.insert(self.use_tos, p.id)
|
||||
end
|
||||
end
|
||||
self:sort(self.enemies)
|
||||
for _, p in ipairs(self.enemies) do
|
||||
if card.skill:targetFilter(p.id, self.use_tos, {}, card) and #p:getCardIds("he") > 0 then
|
||||
self.use_id = card.id
|
||||
table.insert(self.use_tos, p.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_nullification.dismantlement = function(self, card, to, from, positive)
|
||||
if positive then
|
||||
if self:isFriend(to) and not self:isFriend(from) and self.ai_role[from.id] ~= "neutral" then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) or to.id == self.player.id then
|
||||
self.use_id = self.avail_cards[1]
|
||||
end
|
||||
end
|
||||
else
|
||||
if self:isEnemy(to) and self:isEnemy(from) then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) then
|
||||
self.use_id = self.avail_cards[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_use_play["indulgence"] = function(self, card)
|
||||
self:sort(self.enemies, nil, true)
|
||||
for _, p in ipairs(self.enemies) do
|
||||
if card.skill:targetFilter(p.id, self.use_tos, {}, card) then
|
||||
self.use_id = card.id
|
||||
table.insert(self.use_tos, p.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_nullification.indulgence = function(self, card, to, from, positive)
|
||||
if positive then
|
||||
if self:isFriend(to) then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) or to.id == self.player.id then
|
||||
self.use_id = self.avail_cards[1]
|
||||
end
|
||||
end
|
||||
else
|
||||
if self:isEnemy(to) then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) then
|
||||
self.use_id = self.avail_cards[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_use_play["collateral"] = function(self, card)
|
||||
local max = (card.skill:getMaxTargetNum(self.player, card) - 1) * 2
|
||||
self:sort(self.enemies)
|
||||
for _, p in ipairs(self.enemies) do
|
||||
if #self.use_tos < max and card.skill:targetFilter(p.id, {}, {}, card) then
|
||||
for _, pt in ipairs(self.enemies) do
|
||||
if p ~= pt and p:inMyAttackRange(pt) then
|
||||
table.insert(self.use_tos, p.id)
|
||||
table.insert(self.use_tos, pt.id)
|
||||
self.use_id = card.id
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, p in ipairs(self.friends_noself) do
|
||||
if #self.use_tos < max and card.skill:targetFilter(p.id, {}, {}, card) then
|
||||
for _, pt in ipairs(self.enemies) do
|
||||
if p ~= pt and p:inMyAttackRange(pt) then
|
||||
table.insert(self.use_tos, p.id)
|
||||
table.insert(self.use_tos, pt.id)
|
||||
self.use_id = card.id
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_nullification.collateral = function(self, card, to, from, positive)
|
||||
if positive then
|
||||
if self:isFriend(to) and self:isEnemy(from) then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) or to.id == self.player.id then
|
||||
self.use_id = self.avail_cards[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_nullification.ex_nihilo = function(self, card, to, from, positive)
|
||||
if positive then
|
||||
if self:isEnemy(to) then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) then
|
||||
self.use_id = self.avail_cards[1]
|
||||
end
|
||||
end
|
||||
else
|
||||
if self:isFriend(to) then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) or to.id == self.player.id then
|
||||
self.use_id = self.avail_cards[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_nullification.savage_assault = function(self, card, to, from, positive)
|
||||
if positive then
|
||||
if self:isFriend(to) then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) or to.id == self.player.id then
|
||||
self.use_id = self.avail_cards[1]
|
||||
end
|
||||
end
|
||||
else
|
||||
if self:isEnemy(to) then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) then
|
||||
self.use_id = self.avail_cards[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_nullification.archery_attack = function(self, card, to, from, positive)
|
||||
if positive then
|
||||
if self:isFriend(to) then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) or to.id == self.player.id then
|
||||
self.use_id = self.avail_cards[1]
|
||||
end
|
||||
end
|
||||
else
|
||||
if self:isEnemy(to) then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) then
|
||||
self.use_id = self.avail_cards[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_nullification.god_salvation = function(self, card, to, from, positive)
|
||||
if positive then
|
||||
if self:isEnemy(to) and to.hp ~= to.maxHp then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) then
|
||||
self.use_id = self.avail_cards[1]
|
||||
end
|
||||
end
|
||||
else
|
||||
if self:isFriend(to) and to.hp ~= to.maxHp then
|
||||
if #self.avail_cards > 1 or self:isWeak(to) or to.id == self.player.id then
|
||||
self.use_id = self.avail_cards[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_use_play["god_salvation"] = function(self, card)
|
||||
local can = 0
|
||||
for _, p in ipairs(self.enemies) do
|
||||
if p:isWounded()
|
||||
then
|
||||
can = can - 1
|
||||
if self:isWeak(p)
|
||||
then
|
||||
can = can - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, p in ipairs(self.friends) do
|
||||
if p:isWounded()
|
||||
then
|
||||
can = can + 1
|
||||
if self:isWeak(p)
|
||||
then
|
||||
can = can + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
self.use_id = can > 0 and card.id
|
||||
end
|
||||
|
||||
fk.ai_use_play["amazing_grace"] = function(self, card)
|
||||
self.use_id = #self.player:getCardIds("&h") <= self.player.hp and card.id
|
||||
end
|
||||
|
||||
fk.ai_use_play["ex_nihilo"] = function(self, card)
|
||||
self.use_id = card.id
|
||||
end
|
||||
|
||||
fk.ai_use_play["lightning"] = function(self, card)
|
||||
self.use_id = #self.enemies > #self.friends and card.id
|
||||
end
|
||||
|
||||
fk.ai_use_play["peach"] = function(self, card)
|
||||
if self.command == "PlayCard" then
|
||||
self.use_id = self.player.hp ~= self.player.maxHp and self.player.hp < #self.player:getCardIds("h") and card.id
|
||||
else
|
||||
for _, p in ipairs(self.friends) do
|
||||
if p.dying then
|
||||
self.use_id = card.id
|
||||
self.use_tos = { p.id }
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_use_play["duel"] = function(self, card)
|
||||
self:sort(self.enemies)
|
||||
for _, p in ipairs(self.enemies) do
|
||||
if card.skill:targetFilter(p.id, self.use_tos, {}, card) then
|
||||
self.use_id = card.id
|
||||
table.insert(self.use_tos, p.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_skill_invoke["#ice_sword_skill"] = function(self)
|
||||
local damage = self:eventData("Damage")
|
||||
return self:isFriend(damage.to) or not self:isWeak(damage.to) and #damage.to:getCardIds("e") > 1
|
||||
end
|
||||
|
||||
fk.ai_skill_invoke["#double_swords_skill"] = function(self)
|
||||
local use = self:eventData("UseCard")
|
||||
for _, p in ipairs(TargetGroup:getRealTargets(use.tos)) do
|
||||
if not self:isFriend(p) and self.room:getPlayerById(p).gender ~= self.player.gender then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_discard["#double_swords_skill"] = function(self, min_num, num, include_equip, cancelable, pattern, prompt)
|
||||
local use = self:eventData("UseCard")
|
||||
return self:isEnemy(use.from) and { self.player:getCardIds("h")[1] }
|
||||
end
|
||||
|
||||
fk.ai_discard["#axe_skill"] = function(self, min_num, num, include_equip, cancelable, pattern, prompt)
|
||||
local ids = {}
|
||||
local effect = self:eventData("CardEffect")
|
||||
for _, cid in ipairs(self.player:getCardIds("he")) do
|
||||
if Fk:getCardById(cid):matchPattern(pattern) then
|
||||
table.insert(ids, cid)
|
||||
end
|
||||
if #ids >= min_num and self:isEnemy(effect.to)
|
||||
and (self:isWeak(effect.to) or #self.player:getCardIds("he") > 3) then
|
||||
return ids
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
fk.ai_skill_invoke["#kylin_bow_skill"] = function(self)
|
||||
local damage = self:eventData("Damage")
|
||||
return not self:isFriend(damage.to)
|
||||
end
|
||||
|
||||
fk.ai_skill_invoke["#eight_diagram_skill"] = function(self)
|
||||
local effect = self:eventData("CardEffect")
|
||||
return effect and self:isFriend(effect.to)
|
||||
end
|
||||
--]]
|
||||
|
|
|
@ -225,6 +225,29 @@ QString QmlBackend::callLuaFunction(const QString &func_name,
|
|||
return QString(result);
|
||||
}
|
||||
|
||||
QString QmlBackend::evalLuaExp(const QString &lua) {
|
||||
if (!ClientInstance) return "{}";
|
||||
|
||||
lua_State *L = ClientInstance->getLuaState();
|
||||
int err;
|
||||
err = luaL_loadstring(L, lua.toUtf8().constData());
|
||||
if (err != LUA_OK) {
|
||||
qCritical() << lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return "";
|
||||
}
|
||||
err = lua_pcall(L, 0, 1, 0);
|
||||
const char *result = luaL_tolstring(L, -1, NULL);
|
||||
if (err) {
|
||||
qCritical() << result;
|
||||
lua_pop(L, 1);
|
||||
return "";
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
return QString(result);
|
||||
}
|
||||
|
||||
QString QmlBackend::pubEncrypt(const QString &key, const QString &data) {
|
||||
// 在用公钥加密口令时,也随机生成AES密钥/IV,并随着口令一起加密
|
||||
// AES密钥和IV都是固定16字节的,所以可以放在开头
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
Q_INVOKABLE QString translate(const QString &src);
|
||||
Q_INVOKABLE QString callLuaFunction(const QString &func_name,
|
||||
QVariantList params);
|
||||
Q_INVOKABLE QString evalLuaExp(const QString &lua);
|
||||
|
||||
Q_INVOKABLE QString pubEncrypt(const QString &key, const QString &data);
|
||||
Q_INVOKABLE QString loadConf();
|
||||
|
|
Loading…
Reference in New Issue