Delaytrick (#34)
* skip phase (not tested) * Keep alive * fix peach * update * fix move card * indulgence * lightning * complete skip phase
This commit is contained in:
parent
0029949a40
commit
dfa88df214
|
@ -290,6 +290,11 @@ Fk:loadTranslationTable{
|
|||
["normal_damage"] = "无属性",
|
||||
["fire_damage"] = "火属性",
|
||||
["thunder_damage"] = "雷属性",
|
||||
|
||||
["phase_judge"] = "判定阶段",
|
||||
["phase_draw"] = "摸牌阶段",
|
||||
["phase_play"] = "出牌阶段",
|
||||
["phase_discard"] = "弃牌阶段",
|
||||
}
|
||||
|
||||
-- related to sendLog
|
||||
|
@ -319,6 +324,9 @@ Fk:loadTranslationTable{
|
|||
["$DrawCards"] = "%from 摸了 %arg 张牌 %card",
|
||||
["$DiscardCards"] = "%from 弃置了 %arg 张牌 %card",
|
||||
|
||||
-- phase
|
||||
["#PhaseSkipped"] = "%from 跳过了 %arg",
|
||||
|
||||
-- useCard
|
||||
["#UseCard"] = "%from 使用了牌 %card",
|
||||
["#UseCardToTargets"] = "%from 使用了牌 %card,目标是 %to",
|
||||
|
@ -327,6 +335,7 @@ Fk:loadTranslationTable{
|
|||
["#ResponsePlayCard"] = "%from 打出了牌 %card",
|
||||
|
||||
-- judge
|
||||
["#StartJudgeReason"] = "%from 开始了 %arg 的判定",
|
||||
["#InitialJudge"] = "%from 的判定牌为 %card",
|
||||
["#ChangedJudge"] = "%from 发动“%arg”把 %to 的判定牌改为 %card",
|
||||
["#JudgeResult"] = "%from 的判定结果为 %card",
|
||||
|
|
|
@ -54,4 +54,9 @@ function ActiveSkill:onUse(room, cardUseEvent) end
|
|||
---@param cardEffectEvent CardEffectEvent | SkillEffectEvent
|
||||
function ActiveSkill:onEffect(room, cardEffectEvent) end
|
||||
|
||||
-- Delayed Trick Only
|
||||
---@param room Room
|
||||
---@param cardEffectEvent CardEffectEvent | SkillEffectEvent
|
||||
function ActiveSkill:onNullified(room, cardEffectEvent) end
|
||||
|
||||
return ActiveSkill
|
||||
|
|
|
@ -90,6 +90,7 @@ end
|
|||
---@field feasible fun(self: ActiveSkill, selected: integer[], selected_cards: integer[]): boolean
|
||||
---@field on_use fun(self: ActiveSkill, room: Room, cardUseEvent: CardUseStruct): boolean
|
||||
---@field on_effect fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent): boolean
|
||||
---@field on_nullified fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent): boolean
|
||||
|
||||
---@param spec ActiveSkillSpec
|
||||
---@return ActiveSkill
|
||||
|
@ -102,6 +103,7 @@ function fk.CreateActiveSkill(spec)
|
|||
if spec.feasible then skill.feasible = spec.feasible end
|
||||
if spec.on_use then skill.onUse = spec.on_use end
|
||||
if spec.on_effect then skill.onEffect = spec.on_effect end
|
||||
if spec.on_nullified then skill.onNullified = spec.on_nullified end
|
||||
return skill
|
||||
end
|
||||
|
||||
|
|
|
@ -812,7 +812,7 @@ function Room:useCard(cardUseEvent)
|
|||
from = from,
|
||||
to = cardUseEvent.tos or {},
|
||||
})
|
||||
if cardUseEvent.tos then
|
||||
if cardUseEvent.tos and #cardUseEvent.tos > 0 then
|
||||
local to = {}
|
||||
for _, t in ipairs(cardUseEvent.tos) do
|
||||
table.insert(to, t[1])
|
||||
|
@ -927,7 +927,7 @@ function Room:useCard(cardUseEvent)
|
|||
local target = TargetGroup:getRealTargets(cardUseEvent.tos)[1]
|
||||
if not self:getPlayerById(target).dead then
|
||||
local findSameCard = false
|
||||
for _, cardId in ipairs(self:getPlayerById(target):getCardIds(Player.Equip)) do
|
||||
for _, cardId in ipairs(self:getPlayerById(target):getCardIds(Player.Judge)) do
|
||||
if Fk:getCardById(cardId).trueName == Fk:getCardById(cardUseEvent.cardId) then
|
||||
findSameCard = true
|
||||
end
|
||||
|
@ -1026,7 +1026,9 @@ end
|
|||
function Room:doCardEffect(cardEffectEvent)
|
||||
for _, event in ipairs({ fk.PreCardEffect, fk.BeforeCardEffect, fk.CardEffecting, fk.CardEffectFinished }) do
|
||||
if cardEffectEvent.isCancellOut then
|
||||
self.logic:trigger(fk.CardEffectCancelledOut, self:getPlayerById(cardEffectEvent.from), cardEffectEvent)
|
||||
if cardEffectEvent.from then
|
||||
self.logic:trigger(fk.CardEffectCancelledOut, self:getPlayerById(cardEffectEvent.from), cardEffectEvent)
|
||||
end
|
||||
break
|
||||
end
|
||||
|
||||
|
@ -1038,7 +1040,7 @@ function Room:doCardEffect(cardEffectEvent)
|
|||
break
|
||||
end
|
||||
|
||||
if self.logic:trigger(event, self:getPlayerById(cardEffectEvent.from), cardEffectEvent) then
|
||||
if cardEffectEvent.from and self.logic:trigger(event, self:getPlayerById(cardEffectEvent.from), cardEffectEvent) then
|
||||
return
|
||||
end
|
||||
|
||||
|
@ -1252,7 +1254,7 @@ function Room:moveCardTo(card, to_place, target, reason, skill_name, special_nam
|
|||
to = target.id
|
||||
end
|
||||
|
||||
self.moveCards{
|
||||
self:moveCards{
|
||||
ids = ids,
|
||||
from = self.owner_map[ids[1]],
|
||||
to = to,
|
||||
|
@ -1620,10 +1622,19 @@ function Room:judge(data)
|
|||
local who = data.who
|
||||
self.logic:trigger(fk.StartJudge, who, data)
|
||||
data.card = Fk:getCardById(self:getNCards(1)[1])
|
||||
|
||||
if data.reason ~= "" then
|
||||
self:sendLog{
|
||||
type = "#StartJudgeReason",
|
||||
from = who.id,
|
||||
arg = data.reason,
|
||||
}
|
||||
end
|
||||
|
||||
self:sendLog{
|
||||
type = "#InitialJudge",
|
||||
from = who.id,
|
||||
card = {data.card},
|
||||
card = {data.card.id},
|
||||
}
|
||||
self:moveCardTo(data.card, Card.Processing, nil, fk.ReasonPrey)
|
||||
|
||||
|
@ -1632,7 +1643,7 @@ function Room:judge(data)
|
|||
self:sendLog{
|
||||
type = "#JudgeResult",
|
||||
from = who.id,
|
||||
card = {data.card},
|
||||
card = {data.card.id},
|
||||
}
|
||||
|
||||
self.logic:trigger(fk.FinishJudge, who, data)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
---@field reply_ready boolean
|
||||
---@field reply_cancel boolean
|
||||
---@field phases Phase[]
|
||||
---@field skipped_phases Phase[]
|
||||
---@field phase_state table[]
|
||||
---@field phase_index integer
|
||||
local ServerPlayer = Player:subclass("ServerPlayer")
|
||||
|
@ -26,6 +27,7 @@ function ServerPlayer:initialize(_self)
|
|||
self.reply_ready = false
|
||||
self.reply_cancel = false
|
||||
self.phases = {}
|
||||
self.skipped_phases = {}
|
||||
end
|
||||
|
||||
---@param command string
|
||||
|
@ -136,6 +138,13 @@ function ServerPlayer:changePhase(from_phase, to_phase)
|
|||
return false
|
||||
end
|
||||
|
||||
local phase_name_table = {
|
||||
[Player.Judge] = "phase_judge",
|
||||
[Player.Draw] = "phase_draw",
|
||||
[Player.Play] = "phase_play",
|
||||
[Player.Discard] = "phase_discard",
|
||||
}
|
||||
|
||||
---@param phase_table Phase[]
|
||||
function ServerPlayer:play(phase_table)
|
||||
phase_table = phase_table or {}
|
||||
|
@ -161,7 +170,7 @@ function ServerPlayer:play(phase_table)
|
|||
for i = 1, #phases do
|
||||
phase_state[i] = {
|
||||
phase = phases[i],
|
||||
skipped = false
|
||||
skipped = self.skipped_phases[phases[i]] or false
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -180,7 +189,10 @@ function ServerPlayer:play(phase_table)
|
|||
local logic = self.room.logic
|
||||
self.phase = Player.PhaseNone
|
||||
|
||||
local skip = logic:trigger(fk.EventPhaseChanging, self, phase_change)
|
||||
local skip = phase_state[i].skipped
|
||||
if not skip then
|
||||
skip = logic:trigger(fk.EventPhaseChanging, self, phase_change)
|
||||
end
|
||||
phases[i] = phase_change.to
|
||||
phase_state[i].phase = phases[i]
|
||||
|
||||
|
@ -188,7 +200,7 @@ function ServerPlayer:play(phase_table)
|
|||
room:notifyProperty(self, self, "phase")
|
||||
|
||||
local cancel_skip = true
|
||||
if phases[i] ~= Player.NotActive and (phase_state[i].skipped or skip) then
|
||||
if phases[i] ~= Player.NotActive and (skip) then
|
||||
cancel_skip = logic:trigger(fk.EventPhaseSkipping, self)
|
||||
end
|
||||
|
||||
|
@ -201,7 +213,33 @@ function ServerPlayer:play(phase_table)
|
|||
|
||||
if self.phase ~= Player.NotActive then
|
||||
logic:trigger(fk.EventPhaseEnd, self)
|
||||
else break end
|
||||
else
|
||||
self.skipped_phases = {}
|
||||
end
|
||||
else
|
||||
room:sendLog{
|
||||
type = "#PhaseSkipped",
|
||||
from = self.id,
|
||||
arg = phase_name_table[self.phase],
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param phase Phase
|
||||
function ServerPlayer:skip(phase)
|
||||
if not table.contains({
|
||||
Player.Judge,
|
||||
Player.Draw,
|
||||
Player.Play,
|
||||
Player.Discard
|
||||
}, phase) then
|
||||
return
|
||||
end
|
||||
self.skipped_phases[phase] = true
|
||||
for _, t in ipairs(self.phase_state) do
|
||||
if t.phase == phase then
|
||||
t.skipped = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
---@alias CardEffectEvent { from: integer, tos: TargetGroup, cardId: integer, toCardId: integer|null, responseToEvent: CardUseStruct|null, nullifiedTargets: interger[]|null, extraUse: boolean|null, disresponsiveList: integer[]|null, unoffsetableList: integer[]|null, addtionalDamage: integer|null, customFrom: integer|null, cardIdsResponded: integer[]|null }
|
||||
---@alias SkillEffectEvent { from: integer, tos: integer[], cards: integer[] }
|
||||
|
||||
---@alias JudgeStruct { who: ServerPlayer, card: Card, reason: string }
|
||||
|
||||
---@alias CardMoveReason integer
|
||||
|
||||
fk.ReasonJustMove = 1
|
||||
|
|
|
@ -118,7 +118,22 @@ GameRule = fk.CreateTriggerSkill{
|
|||
|
||||
end,
|
||||
[Player.Judge] = function()
|
||||
|
||||
local cards = player:getCardIds(Player.Judge)
|
||||
for i = #cards, 1, -1 do
|
||||
local card = Fk:getCardById(cards[i])
|
||||
room:moveCardTo(card, Card.Processing, nil, fk.ReasonPut, self.name)
|
||||
|
||||
---@type CardEffectEvent
|
||||
local effect_data = {
|
||||
cardId = cards[i],
|
||||
to = player.id,
|
||||
tos = { {player.id} },
|
||||
}
|
||||
room:doCardEffect(effect_data)
|
||||
if effect_data.isCancellOut and card.skill then
|
||||
card.skill:onNullified(room, effect_data)
|
||||
end
|
||||
end
|
||||
end,
|
||||
[Player.Draw] = function()
|
||||
room:drawCards(player, 2, self.name)
|
||||
|
|
|
@ -125,6 +125,11 @@ local peachSkill = fk.CreateActiveSkill{
|
|||
can_use = function(self, player)
|
||||
return player:isWounded()
|
||||
end,
|
||||
on_use = function(self, room, use)
|
||||
if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then
|
||||
use.tos = { { use.from } }
|
||||
end
|
||||
end,
|
||||
on_effect = function(self, room, effect)
|
||||
local to = effect.to
|
||||
local from = effect.from
|
||||
|
@ -367,10 +372,64 @@ extension:addCards({
|
|||
amazingGrace:clone(Card.Heart, 4),
|
||||
})
|
||||
|
||||
local lightningSkill = fk.CreateActiveSkill{
|
||||
name = "lightning_skill",
|
||||
can_use = function(self, player)
|
||||
local judge = player:getCardIds(Player.Judge)
|
||||
for _, id in ipairs(judge) do
|
||||
local cd = Fk:getCardById(id)
|
||||
if cd.name == "lightning" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end,
|
||||
on_use = function(self, room, use)
|
||||
if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then
|
||||
use.tos = { { use.from } }
|
||||
end
|
||||
end,
|
||||
on_effect = function(self, room, effect)
|
||||
local to = room:getPlayerById(effect.to)
|
||||
local judge = {
|
||||
who = to,
|
||||
reason = "lightning",
|
||||
}
|
||||
room:judge(judge)
|
||||
local result = judge.card
|
||||
if result.suit == Card.Spade and result.number >= 2 and result.number <= 9 then
|
||||
room:damage{
|
||||
to = to.id,
|
||||
damage = 3,
|
||||
damageType = fk.ThunderDamage,
|
||||
skillName = self.name,
|
||||
}
|
||||
|
||||
room:moveCards{
|
||||
ids = { effect.cardId },
|
||||
toArea = Card.DiscardPile,
|
||||
moveReason = fk.ReasonPutIntoDiscardPile
|
||||
}
|
||||
else
|
||||
self:onNullified(room, effect)
|
||||
end
|
||||
end,
|
||||
on_nullified = function(self, room, effect)
|
||||
local to = room:getPlayerById(effect.to)
|
||||
local nextp = to:getNextAlive()
|
||||
room:moveCards{
|
||||
ids = { effect.cardId },
|
||||
to = nextp.id,
|
||||
toArea = Card.PlayerJudge,
|
||||
moveReason = fk.ReasonPut
|
||||
}
|
||||
end,
|
||||
}
|
||||
local lightning = fk.CreateDelayedTrickCard{
|
||||
name = "lightning",
|
||||
suit = Card.Spade,
|
||||
number = 1,
|
||||
skill = lightningSkill,
|
||||
}
|
||||
Fk:loadTranslationTable{
|
||||
["lightning"] = "闪电",
|
||||
|
@ -381,10 +440,53 @@ extension:addCards({
|
|||
lightning:clone(Card.Heart, 12),
|
||||
})
|
||||
|
||||
local indulgenceSkill = fk.CreateActiveSkill{
|
||||
name = "indulgence_skill",
|
||||
target_filter = function(self, to_select, selected)
|
||||
if #selected == 0 then
|
||||
local player = Fk:currentRoom():getPlayerById(to_select)
|
||||
if Self ~= player then
|
||||
local judge = player:getCardIds(Player.Judge)
|
||||
for _, id in ipairs(judge) do
|
||||
local cd = Fk:getCardById(id)
|
||||
if cd.name == "indulgence" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end,
|
||||
feasible = function(self, selected)
|
||||
return #selected == 1
|
||||
end,
|
||||
on_effect = function(self, room, effect)
|
||||
local to = room:getPlayerById(effect.to)
|
||||
local judge = {
|
||||
who = to,
|
||||
reason = "indulgence",
|
||||
}
|
||||
room:judge(judge)
|
||||
local result = judge.card
|
||||
if result.suit ~= Card.Heart then
|
||||
to:skip(Player.Play)
|
||||
end
|
||||
self:onNullified(room, effect)
|
||||
end,
|
||||
on_nullified = function(self, room, effect)
|
||||
room:moveCards{
|
||||
ids = { effect.cardId },
|
||||
toArea = Card.DiscardPile,
|
||||
moveReason = fk.ReasonPutIntoDiscardPile
|
||||
}
|
||||
end,
|
||||
}
|
||||
local indulgence = fk.CreateDelayedTrickCard{
|
||||
name = "indulgence",
|
||||
suit = Card.Spade,
|
||||
number = 6,
|
||||
skill = indulgenceSkill,
|
||||
}
|
||||
Fk:loadTranslationTable{
|
||||
["indulgence"] = "乐不思蜀",
|
||||
|
|
|
@ -24,6 +24,7 @@ void ClientSocket::init()
|
|||
this, &ClientSocket::getMessage);
|
||||
connect(socket, &QTcpSocket::errorOccurred,
|
||||
this, &ClientSocket::raiseError);
|
||||
socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
|
||||
}
|
||||
|
||||
void ClientSocket::connectToHost(const QString &address, ushort port)
|
||||
|
|
Loading…
Reference in New Issue