初步ai逻辑 (#270)

大部分修改的地方都在代码里加了注释

---------

Co-authored-by: notify <notify-ctrl@qq.com>
Co-authored-by: xxyheaven <1433191064@qq.com>
Co-authored-by: YoumuKon <38815081+YoumuKon@users.noreply.github.com>
This commit is contained in:
luazyxs 2023-10-07 03:22:57 +08:00 committed by GitHub
parent f97df65ac6
commit d1619672a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 2296 additions and 43 deletions

BIN
audio/system/recast.mp3 Normal file

Binary file not shown.

View File

@ -329,12 +329,18 @@ end
function Player:getCardIds(playerAreas, specialName)
local rightAreas = { Player.Hand, Player.Equip, Player.Judge }
playerAreas = playerAreas or rightAreas
local cardIds = {}
if type(playerAreas) == "string" then
local str = playerAreas
playerAreas = {}
if str:find("h") then
table.insert(playerAreas, Player.Hand)
end
if str:find("&") then--增加特殊区域
for k, v in pairs(self.special_cards) do
if k:endsWith("&") then table.insertTable(cardIds, v) end
end
end
if str:find("e") then
table.insert(playerAreas, Player.Equip)
end
@ -345,8 +351,7 @@ function Player:getCardIds(playerAreas, specialName)
assert(type(playerAreas) == "number" or type(playerAreas) == "table")
local areas = type(playerAreas) == "table" and playerAreas or { playerAreas }
local rightAreas = { Player.Hand, Player.Equip, Player.Judge, Player.Special }
local cardIds = {}
rightAreas = { Player.Hand, Player.Equip, Player.Judge, Player.Special }
for _, area in ipairs(areas) do
assert(table.contains(rightAreas, area))
assert(area ~= Player.Special or type(specialName) == "string")

View File

@ -134,13 +134,15 @@ random_cb.AskForUseCard = function(self, jsonData)
local cancelable = data[4] or true
local exp = Exppattern:Parse(pattern)
local avail_cards = table.filter(player:getCardIds("he"), function(id)
return exp:match(Fk:getCardById(id)) and not player:prohibitUse(Fk:getCardById(id))
local avail_cards = table.map(player:getCardIds("he"),
function(id) return Fk:getCardById(id) end)
avail_cards = table.filter(avail_cards, function(c)
return exp:match(c) and not player:prohibitUse(c)
end)
if #avail_cards > 0 then
if math.random() < 0.25 then return "" end
for _, card in ipairs(avail_cards) do
local skill = Fk:getCardById(card).skill
local skill = card.skill
local max_try_times = 100
local selected_targets = {}
local min = skill:getMinTargetNum()
@ -148,22 +150,19 @@ random_cb.AskForUseCard = function(self, jsonData)
local min_card = skill:getMinCardNum()
local max_card = skill:getMaxCardNum()
for _ = 0, max_try_times do
if skill:feasible(selected_targets, {card}, self.player, card) then break end
if skill:feasible(selected_targets, { card.id }, self.player, card) then
return json.encode{
card = table.random(avail_cards).id,
targets = selected_targets,
}
end
local avail_targets = table.filter(self.room:getAlivePlayers(), function(p)
local ret = skill:targetFilter(p.id, selected_targets, {card}, card or Fk:cloneCard'zixing')
return ret
return skill:targetFilter(p.id, selected_targets, {card.id}, card or Fk:cloneCard'zixing')
end)
avail_targets = table.map(avail_targets, function(p) return p.id end)
if #avail_targets == 0 and #avail_cards == 0 then break end
table.insertIfNeed(selected_targets, table.random(avail_targets))
table.insertIfNeed({card}, table.random(avail_cards))
end
if skill:feasible(selected_targets, {card}, self.player, card) then
return json.encode{
card = table.random(avail_cards),
targets = selected_targets,
}
end
end
end

File diff suppressed because it is too large Load Diff

View File

@ -44,7 +44,9 @@ function GameLogic:run()
self.room.game_started = true
room:doBroadcastNotify("StartGame", "")
room:adjustSeats()
for _, p in ipairs(room.players) do
p.ai = SmartAI:new(p)
end
self:chooseGenerals()
self:buildPlayerCircle()

View File

@ -3071,6 +3071,7 @@ function Room:recastCard(card_ids, who, skillName)
moveReason = fk.ReasonPutIntoDiscardPile,
proposer = who.id
})
self:broadcastPlaySound("./audio/system/recast")
self:sendLog{
type = skillName == "recast" and "#Recast" or "#RecastBySkill",
from = who.id,

View File

@ -0,0 +1,178 @@
fk.ai_card.thunder__slash = fk.ai_card.slash
fk.ai_use_play.thunder__slash = fk.ai_use_play.slash
fk.ai_card.fire__slash = fk.ai_card.slash
fk.ai_use_play.fire__slash = fk.ai_use_play.slash
fk.ai_card.analeptic = {
intention = 60, -- 身份值
value = 5, -- 卡牌价值
priority = 3 -- 使用优先值
}
fk.ai_use_play["analeptic"] = function(self, card)
local cards = table.map(self.player:getCardIds("&he"), function(id)
return Fk:getCardById(id)
end)
self:sortValue(cards)
for _, sth in ipairs(self:getActives("slash")) do
local slash = nil
if sth:isInstanceOf(Card) then
if sth.skill:canUse(self.player, sth) and not self.player:prohibitUse(sth) then
slash = sth
end
else
local selected = {}
for _, c in ipairs(cards) do
if sth:cardFilter(c.id, selected) then
table.insert(selected, c.id)
end
end
local tc = sth:viewAs(selected)
if tc and tc:matchPattern("slash") and tc.skill:canUse(self.player, tc) and not self.player:prohibitUse(tc) then
slash = tc
end
end
if slash then
fk.ai_use_play.slash(self, slash)
if self.use_id then
self.use_id = card.id
self.use_tos = {}
break
end
end
end
end
fk.ai_card.iron_chain = {
intention = function(self, card, from)
if self.player.chained then
return -80
end
return 80
end, -- 身份值
value = 2, -- 卡牌价值
priority = 3 -- 使用优先值
}
fk.ai_use_play["iron_chain"] = function(self, card)
for _, p in ipairs(self.friends) do
if card.skill:targetFilter(p.id, self.use_tos, {}, card) and p.chained then
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 not p.chained then
table.insert(self.use_tos, p.id)
end
end
if #self.use_tos < 2 then
self.use_tos = {}
else
self.use_id = card.id
end
end
fk.ai_use_play["recast"] = function(self, card)
if self.command == "PlayCard" then
self.use_id = card.id
self.special_skill = "recast"
end
end
fk.ai_card.fire_attack = {
intention = 90, -- 身份值
value = 3, -- 卡牌价值
priority = 4 -- 使用优先值
}
fk.ai_use_play["fire_attack"] = 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 #self.player:getCardIds("h") > 2 then
self.use_id = card.id
table.insert(self.use_tos, p.id)
end
end
end
fk.ai_discard["fire_attack_skill"] = function(self, min_num, num, include_equip, cancelable, pattern, prompt)
local use = self:eventData("UseCard")
for _, p in ipairs(TargetGroup:getRealTargets(use.tos)) do
if self:isEnemie(p) then
local cards = table.map(self.player:getCardIds("h"), function(id)
return Fk:getCardById(id)
end)
local exp = Exppattern:Parse(pattern)
cards = table.filter(cards, function(c)
return exp:match(c)
end)
if #cards > 0 then
self:sortValue(cards)
return { cards[1].id }
end
end
end
end
fk.ai_nullification.fire_attack = function(self, card, to, from, positive)
if positive then
if self:isFriend(to) and #to:getCardIds("h") > 0 and #from:getCardIds("h") > 0 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:isEnemie(to) and #to:getCardIds("h") > 0 and #from:getCardIds("h") > 1 then
if #self.avail_cards > 1 or self:isWeak(to) then
self.use_id = self.avail_cards[1]
end
end
end
end
fk.ai_card.fire_attack = {
intention = 120, -- 身份值
value = 2, -- 卡牌价值
priority = 2 -- 使用优先值
}
fk.ai_use_play["supply_shortage"] = 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 not p.chained then
self.use_id = card.id
table.insert(self.use_tos, p.id)
end
end
end
fk.ai_nullification.supply_shortage = 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:isEnemie(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_card.supply_shortage = {
intention = 130, -- 身份值
value = 2, -- 卡牌价值
priority = 1 -- 使用优先值
}
fk.ai_skill_invoke["#fan_skill"] = function(self)
local use = self:eventData("UseCard")
for _, p in ipairs(TargetGroup:getRealTargets(use.tos)) do
if not self:isFriend(p) then
return true
end
end
end

View File

@ -182,7 +182,11 @@ local ironChainCardSkill = fk.CreateActiveSkill{
mod_target_filter = function(self, to_select, selected, user, card, distance_limited)
return true
end,
target_filter = function() return true end,
target_filter = function(self, to_select, selected, _, card)
if #selected < self:getMaxTargetNum(Self, card) then
return self:modTargetFilter(to_select, selected, Self.id, card)
end
end,
on_effect = function(self, room, cardEffectEvent)
local to = room:getPlayerById(cardEffectEvent.to)
to:setChainState(not to.chained)
@ -208,10 +212,13 @@ local fireAttackSkill = fk.CreateActiveSkill{
name = "fire_attack_skill",
target_num = 1,
mod_target_filter = function(self, to_select, selected, user, card, distance_limited)
return not Fk:currentRoom():getPlayerById(to_select):isKongcheng()
local to = Fk:currentRoom():getPlayerById(to_select)
return not to:isKongcheng()
end,
target_filter = function(self, to_select)
return self:modTargetFilter(to_select)
target_filter = function(self, to_select, selected, _, card)
if #selected < self:getMaxTargetNum(Self, card) then
return self:modTargetFilter(to_select, selected, Self.id, card)
end
end,
on_effect = function(self, room, cardEffectEvent)
local from = room:getPlayerById(cardEffectEvent.from)

View File

@ -0,0 +1,262 @@
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
fk.ai_card["hujia"] = { priority = 10 }
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
end
fk.ai_response_card["#jijiang-ask"] = fk.ai_response_card["#hujia-ask"]
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
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
end
fk.ai_skill_invoke["tiandu"] = true
fk.ai_skill_invoke["yiji"] = true
fk.ai_skill_invoke["luoshen"] = true
fk.ai_skill_invoke["guanxing"] = true
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:isEnemie(p) then
return true
end
end
end
fk.ai_skill_invoke["jizhi"] = true
fk.ai_skill_invoke["keji"] = true
fk.ai_skill_invoke["yingzi"] = true
fk.ai_skill_invoke["lianying"] = true
fk.ai_skill_invoke["xiaoji"] = true
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:isEnemie(p) and #self.use_tos < num then
table.insert(self.use_tos, pid)
end
end
end
fk.ai_use_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:isEnemie(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

View File

@ -10,9 +10,11 @@ local jianxiong = fk.CreateTriggerSkill{
anim_type = "masochism",
events = {fk.Damaged},
can_trigger = function(self, event, target, player, data)
local room = target.room
return target == player and player:hasSkill(self.name) and data.card and
table.every(data.card:isVirtual() and data.card.subcards or {data.card.id}, function(id) return room:getCardArea(id) == Card.Processing end)
if target == player and player:hasSkill(self.name) and data.card then
local room = player.room
local subcards = data.card:isVirtual() and data.card.subcards or {data.card.id}
return #subcards>0 and table.every(subcards, function(id) return room:getCardArea(id) == Card.Processing end)
end
end,
on_use = function(self, event, target, player, data)
player.room:obtainCard(player.id, data.card, true, fk.ReasonJustMove)
@ -282,6 +284,7 @@ local yiji = fk.CreateTriggerSkill{
for _, id in ipairs(ids) do
room:setCardMark(Fk:getCardById(id), "yiji", 1)
end
player.tag["yiji_ids"] = ids --存储遗技卡牌表
while table.find(ids, function(id) return Fk:getCardById(id):getMark("yiji") > 0 end) do
if not room:askForUseActiveSkill(player, "yiji_active", "#yiji-give", true) then
for _, id in ipairs(ids) do
@ -491,7 +494,7 @@ local jijiangResponse = fk.CreateTriggerSkill{
end
if event == fk.PreCardUse and player.phase == Player.Play then
room:setPlayerMark(player, "jijiang-failed-phase", 1)
room:setPlayerMark(player, "jijiang-failed-phase", 1)
end
return true
end,

View File

@ -0,0 +1,438 @@
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
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
end
fk.ai_ask_usecard["#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
end
fk.ai_ask_usecard["#slash-jinks"] = fk.ai_ask_usecard["#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
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]
end
end
else
if self:isEnemie(to) and self:isEnemie(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:isEnemie(to) and self:isEnemie(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:isEnemie(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:isEnemie(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:isEnemie(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:isEnemie(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:isEnemie(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:isEnemie(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:isEnemie(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:isEnemie(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

View File

@ -172,13 +172,13 @@ extension:addCards({
local dismantlementSkill = fk.CreateActiveSkill{
name = "dismantlement_skill",
target_num = 1,
mod_target_filter = function(self, to_select, selected, user)
mod_target_filter = function(self, to_select, selected, user, card)
local player = Fk:currentRoom():getPlayerById(to_select)
return Fk:currentRoom():getPlayerById(user) ~= player and not player:isAllNude()
return user ~= to_select and not player:isAllNude()
end,
target_filter = function(self, to_select, selected)
if #selected < self:getMaxTargetNum(Self) then
return self:modTargetFilter(to_select, selected, Self.id)
target_filter = function(self, to_select, selected, _, card)
if #selected < self:getMaxTargetNum(Self, card) then
return self:modTargetFilter(to_select, selected, Self.id, card)
end
end,
on_effect = function(self, room, effect)
@ -216,7 +216,7 @@ local snatchSkill = fk.CreateActiveSkill{
return from ~= player and not (player:isAllNude() or (distance_limited and not self:withinDistanceLimit(from, false, card, player)))
end,
target_filter = function(self, to_select, selected, _, card)
if #selected == 0 then
if #selected < self:getMaxTargetNum(Self, card) then
return self:modTargetFilter(to_select, selected, Self.id, card, true)
end
end,
@ -247,12 +247,12 @@ extension:addCards({
local duelSkill = fk.CreateActiveSkill{
name = "duel_skill",
mod_target_filter = function(self, to_select, selected, user)
mod_target_filter = function(self, to_select, selected, user, card)
return user ~= to_select
end,
target_filter = function(self, to_select, selected)
if #selected == 0 then
return self:modTargetFilter(to_select, selected, Self.id)
target_filter = function(self, to_select, selected, _, card)
if #selected < self:getMaxTargetNum(Self, card) then
return self:modTargetFilter(to_select, selected, Self.id, card)
end
end,
target_num = 1,
@ -334,19 +334,33 @@ local collateralSkill = fk.CreateActiveSkill{
name = "collateral_skill",
mod_target_filter = function(self, to_select, selected, user, card, distance_limited)
local player = Fk:currentRoom():getPlayerById(to_select)
return user ~= player.id and player:getEquipment(Card.SubtypeWeapon)
return user ~= to_select and player:getEquipment(Card.SubtypeWeapon)
end,
target_filter = function(self, to_select, selected)
local player = Fk:currentRoom():getPlayerById(to_select)
if #selected == 0 then
return Self ~= player and player:getEquipment(Card.SubtypeWeapon)
elseif #selected == 1 then
return Fk:currentRoom():getPlayerById(selected[1]):inMyAttackRange(player)
target_filter = function(self, to_select, selected, _, card)
if #selected >= (self:getMaxTargetNum(Self, card) - 1) * 2 then
return false--修改借刀的目标选择
elseif #selected % 2 == 0 then
return self:modTargetFilter(to_select, selected, Self.id, card)
else
local player = Fk:currentRoom():getPlayerById(to_select)
local from = Fk:currentRoom():getPlayerById(selected[#selected])
return self:modTargetFilter(selected[#selected], selected, Self.id, card)
and from:inMyAttackRange(player) and not from:isProhibited(player, Fk:cloneCard("slash"))
end
end,
target_num = 2,
on_use = function(self, room, cardUseEvent)
cardUseEvent.tos = { { cardUseEvent.tos[1][1], cardUseEvent.tos[2][1] } }
local tos = {}
local exclusive = {}
for i, pid in ipairs(TargetGroup:getRealTargets(cardUseEvent.tos)) do
if i % 2 == 1 then
exclusive = { pid }
else
table.insert(exclusive, pid)
table.insert(tos, exclusive)
end
end
cardUseEvent.tos = tos
end,
on_effect = function(self, room, effect)
local to = room:getPlayerById(effect.to)