老朱然相关:终止结算、终止回合
执行新阶段
This commit is contained in:
notify 2023-04-22 15:52:26 +08:00 committed by GitHub
parent 7e8b798c05
commit 5888df6e7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 265 additions and 185 deletions

View File

@ -8,6 +8,7 @@
fk.NonTrigger = 1 fk.NonTrigger = 1
fk.GameStart = 2 fk.GameStart = 2
fk.TurnStart = 3 fk.TurnStart = 3
fk.TurnEnd = 72
fk.EventPhaseStart = 4 fk.EventPhaseStart = 4
fk.EventPhaseProceeding = 5 fk.EventPhaseProceeding = 5
fk.EventPhaseEnd = 6 fk.EventPhaseEnd = 6
@ -92,4 +93,6 @@ fk.PindianCardsDisplayed = 69
fk.PindianResultConfirmed = 70 fk.PindianResultConfirmed = 70
fk.PindianFinished = 71 fk.PindianFinished = 71
-- 72 = TurnEnd
fk.NumOfEvents = 72 fk.NumOfEvents = 72

View File

@ -2,8 +2,33 @@
GameEvent.functions[GameEvent.DrawInitial] = function(self) GameEvent.functions[GameEvent.DrawInitial] = function(self)
local room = self.room local room = self.room
for _, p in ipairs(room.alive_players) do for _, player in ipairs(room.alive_players) do
room.logic:trigger(fk.DrawInitialCards, p, { num = 4 }) local draw_data = { num = 4 }
room.logic:trigger(fk.DrawInitialCards, player, draw_data)
if draw_data.num > 0 then
-- TODO: need a new function to call the UI
local cardIds = room:getNCards(draw_data.num)
player:addCards(Player.Hand, cardIds)
for _, id in ipairs(cardIds) do
Fk:filterCard(id, player)
end
local move_to_notify = {} ---@type CardsMoveStruct
move_to_notify.toArea = Card.PlayerHand
move_to_notify.to = player.id
move_to_notify.moveInfo = {}
move_to_notify.moveReason = fk.ReasonDraw
for _, id in ipairs(cardIds) do
table.insert(move_to_notify.moveInfo,
{ cardId = id, fromArea = Card.DrawPile })
end
room:notifyMoveCards(nil, {move_to_notify})
for _, id in ipairs(cardIds) do
room:setCardArea(id, Card.PlayerHand, player.id)
end
room.logic:trigger(fk.AfterDrawInitialCards, player, data)
end
end end
end end
@ -12,6 +37,12 @@ GameEvent.functions[GameEvent.Round] = function(self)
local logic = room.logic local logic = room.logic
local p local p
if room:getTag("FirstRound") then
room:setTag("FirstRound", false)
end
room:setTag("RoundCount", room:getTag("RoundCount") + 1)
room:doBroadcastNotify("UpdateRoundNum", room:getTag("RoundCount"))
logic:trigger(fk.RoundStart, room.current) logic:trigger(fk.RoundStart, room.current)
repeat repeat
@ -24,14 +55,165 @@ GameEvent.functions[GameEvent.Round] = function(self)
logic:trigger(fk.RoundEnd, p) logic:trigger(fk.RoundEnd, p)
end end
GameEvent.cleaners[GameEvent.Round] = function(self)
local room = self.room
for _, p in ipairs(room.players) do
p:setCardUseHistory("", 0, Player.HistoryRound)
p:setSkillUseHistory("", 0, Player.HistoryRound)
for name, _ in pairs(p.mark) do
if name:endsWith("-round") then
room:setPlayerMark(p, name, 0)
end
end
end
end
GameEvent.functions[GameEvent.Turn] = function(self) GameEvent.functions[GameEvent.Turn] = function(self)
local room = self.room local room = self.room
room.logic:trigger(fk.TurnStart, room.current) room.logic:trigger(fk.TurnStart, room.current)
room:sendLog{ type = "$AppendSeparator" }
local player = room.current local player = room.current
if not player.faceup then if not player.faceup then
player:turnOver() player:turnOver()
elseif not player.dead then elseif not player.dead then
player:play() player:play()
end end
room.logic:trigger(fk.TurnEnd, room.current)
end
GameEvent.cleaners[GameEvent.Turn] = function(self)
local room = self.room
for _, p in ipairs(room.players) do
p:setCardUseHistory("", 0, Player.HistoryTurn)
p:setSkillUseHistory("", 0, Player.HistoryTurn)
for name, _ in pairs(p.mark) do
if name:endsWith("-turn") then
room:setPlayerMark(p, name, 0)
end
end
end
if self.interrupted then
room.current.phase = Player.Finish
room.logic:trigger(fk.EventPhaseStart, room.current, nil, true)
room.logic:trigger(fk.EventPhaseEnd, room.current, nil, true)
room.current.phase = Player.NotActive
room:notifyProperty(room.current, room.current, "phase")
room.logic:trigger(fk.EventPhaseChanging, room.current,
{ from = Player.Finish, to = Player.NotActive }, true)
room.logic:trigger(fk.EventPhaseStart, room.current, nil, true)
room.current.skipped_phases = {}
room.logic:trigger(fk.TurnEnd, room.current, nil, true)
end
end
GameEvent.functions[GameEvent.Phase] = function(self)
local room = self.room
local logic = room.logic
local player = self.data[1]
if not logic:trigger(fk.EventPhaseStart, player) then
if player.phase ~= Player.NotActive then
logic:trigger(fk.EventPhaseProceeding, player)
switch(player.phase, {
[Player.PhaseNone] = function()
error("You should never proceed PhaseNone")
end,
[Player.RoundStart] = function()
end,
[Player.Start] = function()
end,
[Player.Judge] = function()
local cards = player:getCardIds(Player.Judge)
for i = #cards, 1, -1 do
local card
card = player:removeVirtualEquip(cards[i])
if not card then
card = Fk:getCardById(cards[i])
end
room:moveCardTo(card, Card.Processing, nil, fk.ReasonPut, self.name)
---@type CardEffectEvent
local effect_data = {
card = card,
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()
local data = {
n = 2
}
room.logic:trigger(fk.DrawNCards, player, data)
room:drawCards(player, data.n, self.name)
room.logic:trigger(fk.AfterDrawNCards, player, data)
end,
[Player.Play] = function()
while not player.dead do
room:notifyMoveFocus(player, "PlayCard")
local result = room:doRequest(player, "PlayCard", player.id)
if result == "" then break end
local use = room:handleUseCardReply(player, result)
if use then
room:useCard(use)
end
end
end,
[Player.Discard] = function()
local discardNum = #player:getCardIds(Player.Hand) - player:getMaxCards()
if discardNum > 0 then
room:askForDiscard(player, discardNum, discardNum, false, self.name)
end
end,
[Player.Finish] = function()
end,
[Player.NotActive] = function()
end,
})
end
end
if self.phase ~= Player.NotActive then
logic:trigger(fk.EventPhaseEnd, self)
else
self.skipped_phases = {}
end
end
GameEvent.cleaners[GameEvent.Phase] = function(self)
local room = self.room
local player = self.data[1]
for _, p in ipairs(room.players) do
p:setCardUseHistory("", 0, Player.HistoryPhase)
p:setSkillUseHistory("", 0, Player.HistoryPhase)
for name, _ in pairs(p.mark) do
if name:endsWith("-phase") then
room:setPlayerMark(p, name, 0)
end
end
end
if self.interrupted then
room.logic:trigger(fk.EventPhaseEnd, player, nil, true)
end
end end

View File

@ -31,9 +31,10 @@ dofile "lua/server/events/judge.lua"
GameEvent.DrawInitial = 15 GameEvent.DrawInitial = 15
GameEvent.Round = 16 GameEvent.Round = 16
GameEvent.Turn = 17 GameEvent.Turn = 17
GameEvent.Phase = 18
dofile "lua/server/events/gameflow.lua" dofile "lua/server/events/gameflow.lua"
GameEvent.Pindian = 18 GameEvent.Pindian = 19
dofile "lua/server/events/pindian.lua" dofile "lua/server/events/pindian.lua"
-- TODO: fix this -- TODO: fix this
@ -55,7 +56,10 @@ local eventTranslations = {
[GameEvent.DrawInitial] = "GameEvent.DrawInitial", [GameEvent.DrawInitial] = "GameEvent.DrawInitial",
[GameEvent.Round] = "GameEvent.Round", [GameEvent.Round] = "GameEvent.Round",
[GameEvent.Turn] = "GameEvent.Turn", [GameEvent.Turn] = "GameEvent.Turn",
[GameEvent.Phase] = "GameEvent.Phase",
[GameEvent.Pindian] = "GameEvent.Pindian", [GameEvent.Pindian] = "GameEvent.Pindian",
[GameEvent.BreakEvent] = "GameEvent.BreakEvent",
} }
function GameEvent.static:translate(id) function GameEvent.static:translate(id)

View File

@ -25,11 +25,15 @@ function GameEvent:initialize(event, ...)
self.event = event self.event = event
self.data = { ... } self.data = { ... }
self.main_func = wrapCoFunc(GameEvent.functions[event], self) or dummyFunc self.main_func = wrapCoFunc(GameEvent.functions[event], self) or dummyFunc
self.clear_func = wrapCoFunc(GameEvent.cleaners[event], self) or dummyFunc self.clear_func = GameEvent.cleaners[event] or dummyFunc
self.extra_clear_funcs = {} self.extra_clear_funcs = {}
self.interrupted = false self.interrupted = false
end end
function GameEvent:__tostring()
return GameEvent:translate(self.event)
end
function GameEvent:findParent(eventType) function GameEvent:findParent(eventType)
local e = self.parent local e = self.parent
repeat repeat
@ -46,6 +50,19 @@ function GameEvent:clear()
self:clear_func() self:clear_func()
end end
local function breakEvent(self, extra_yield_result)
local cancelEvent = GameEvent:new(GameEvent.BreakEvent, self)
local notcanceled = cancelEvent:exec()
local ret, extra_ret = false, nil
if not notcanceled then
self.interrupted = true
self:clear()
ret = true
extra_ret = extra_yield_result
end
return ret, extra_ret
end
function GameEvent:exec() function GameEvent:exec()
local room = self.room local room = self.room
local logic = room.logic local logic = room.logic
@ -67,6 +84,7 @@ function GameEvent:exec()
self.interrupted = true self.interrupted = true
self:clear() self:clear()
ret = true ret = true
coroutine.close(co)
break break
end end
@ -76,23 +94,27 @@ function GameEvent:exec()
elseif type(yield_result) == "table" and yield_result.class elseif type(yield_result) == "table" and yield_result.class
and yield_result:isInstanceOf(GameEvent) then and yield_result:isInstanceOf(GameEvent) then
-- yield to corresponding GameEvent, first pop self from stack
self.interrupted = true
self:clear()
logic.game_event_stack:pop(self)
-- then, call yield if self ~= yield_result then
coroutine.yield(yield_result) -- yield to corresponding GameEvent, first pop self from stack
self.interrupted = true
self:clear()
logic.game_event_stack:pop(self)
coroutine.close(co)
-- then, call yield
coroutine.yield(yield_result, extra_yield_result)
elseif extra_yield_result == "__breakEvent" then
if breakEvent(self) then
coroutine.close(co)
break
end
end
elseif yield_result == "__breakEvent" then elseif yield_result == "__breakEvent" then
-- try to break this event -- try to break this event
local cancelEvent = GameEvent:new(GameEvent.BreakEvent, self) if breakEvent(self) then
local notcanceled = cancelEvent:exec() coroutine.close(co)
if not notcanceled then
self.interrupted = true
self:clear()
ret = true
extra_ret = extra_yield_result
break break
end end
@ -100,6 +122,7 @@ function GameEvent:exec()
-- normally exit, simply break the loop -- normally exit, simply break the loop
self:clear() self:clear()
extra_ret = yield_result extra_ret = yield_result
coroutine.close(co)
break break
end end
end end
@ -108,4 +131,9 @@ function GameEvent:exec()
return ret, extra_ret return ret, extra_ret
end end
function GameEvent:shutdown()
-- yield to self and break
coroutine.yield(self, "__breakEvent")
end
return GameEvent return GameEvent

View File

@ -271,7 +271,7 @@ end
---@param event Event ---@param event Event
---@param target ServerPlayer ---@param target ServerPlayer
---@param data any ---@param data any
function GameLogic:trigger(event, target, data) function GameLogic:trigger(event, target, data, refresh_only)
local room = self.room local room = self.room
local broken = false local broken = false
local skills = self.skill_table[event] or {} local skills = self.skill_table[event] or {}
@ -291,7 +291,7 @@ function GameLogic:trigger(event, target, data)
player = player.next player = player.next
end until player == _target end end until player == _target end
if #skills == 0 then return end if #skills == 0 or refresh_only then return end
local prio_tab = self.skill_priority_table[event] local prio_tab = self.skill_priority_table[event]
local prev_prio = math.huge local prev_prio = math.huge
@ -368,7 +368,7 @@ function GameLogic:dumpEventStack(detailed)
end end
if not detailed then if not detailed then
print("Stack level #" .. i .. ": " .. GameEvent:translate(top.event)) print("Stack level #" .. i .. ": " .. tostring(top))
else else
print("\nStack level #" .. i .. ":") print("\nStack level #" .. i .. ":")
inspect{ inspect{
@ -388,4 +388,9 @@ function GameLogic:breakEvent(ret)
coroutine.yield("__breakEvent", ret) coroutine.yield("__breakEvent", ret)
end end
function GameLogic:breakTurn()
local event = self:getCurrentEvent():findParent(GameEvent.Turn)
event:shutdown()
end
return GameLogic return GameLogic

View File

@ -92,6 +92,9 @@ function Room:initialize(_room)
-- If ret == true, then when err_msg is true, that means no request -- If ret == true, then when err_msg is true, that means no request
end end
coroutine.close(main_co)
coroutine.close(request_co)
if not self.game_finished then if not self.game_finished then
self:doBroadcastNotify("GameOver", "") self:doBroadcastNotify("GameOver", "")
self.room:gameOver() self.room:gameOver()

View File

@ -333,19 +333,23 @@ function ServerPlayer:changePhase(from_phase, to_phase)
table.remove(self.phases, 1) table.remove(self.phases, 1)
end end
if not logic:trigger(fk.EventPhaseStart, self) then GameEvent(GameEvent.Phase, self):exec()
if self.phase ~= Player.NotActive then
logic:trigger(fk.EventPhaseProceeding, self)
end
end
if self.phase ~= Player.NotActive then
logic:trigger(fk.EventPhaseEnd, self)
end
return false return false
end end
function ServerPlayer:gainAnExtraPhase(phase)
local room = self.room
local current = self.phase
self.phase = phase
room:notifyProperty(self, self, "phase")
GameEvent(GameEvent.Phase, self):exec()
self.phase = current
room:notifyProperty(self, self, "phase")
end
local phase_name_table = { local phase_name_table = {
[Player.Judge] = "phase_judge", [Player.Judge] = "phase_judge",
[Player.Draw] = "phase_draw", [Player.Draw] = "phase_draw",
@ -413,17 +417,7 @@ function ServerPlayer:play(phase_table)
end end
if (not skip) or (cancel_skip) then if (not skip) or (cancel_skip) then
if not logic:trigger(fk.EventPhaseStart, self) then GameEvent(GameEvent.Phase, self):exec()
if self.phase ~= Player.NotActive then
logic:trigger(fk.EventPhaseProceeding, self)
end
end
if self.phase ~= Player.NotActive then
logic:trigger(fk.EventPhaseEnd, self)
else
self.skipped_phases = {}
end
else else
room:sendLog{ room:sendLog{
type = "#PhaseSkipped", type = "#PhaseSkipped",

View File

@ -41,9 +41,7 @@ end
GameRule = fk.CreateTriggerSkill{ GameRule = fk.CreateTriggerSkill{
name = "game_rule", name = "game_rule",
events = { events = {
fk.GameStart, fk.DrawInitialCards, fk.GameStart,
fk.EventPhaseProceeding, fk.EventPhaseEnd, fk.EventPhaseChanging,
fk.RoundStart,
fk.AskForPeaches, fk.AskForPeachesDone, fk.AskForPeaches, fk.AskForPeachesDone,
fk.GameOverJudge, fk.BuryVictim, fk.GameOverJudge, fk.BuryVictim,
}, },
@ -67,146 +65,6 @@ GameRule = fk.CreateTriggerSkill{
end end
switch(event, { switch(event, {
[fk.DrawInitialCards] = function()
if data.num > 0 then
-- TODO: need a new function to call the UI
local cardIds = room:getNCards(data.num)
player:addCards(Player.Hand, cardIds)
for _, id in ipairs(cardIds) do
Fk:filterCard(id, player)
end
local move_to_notify = {} ---@type CardsMoveStruct
move_to_notify.toArea = Card.PlayerHand
move_to_notify.to = player.id
move_to_notify.moveInfo = {}
move_to_notify.moveReason = fk.ReasonDraw
for _, id in ipairs(cardIds) do
table.insert(move_to_notify.moveInfo,
{ cardId = id, fromArea = Card.DrawPile })
end
room:notifyMoveCards(nil, {move_to_notify})
for _, id in ipairs(cardIds) do
room:setCardArea(id, Card.PlayerHand, player.id)
end
room.logic:trigger(fk.AfterDrawInitialCards, player, data)
end
end,
[fk.RoundStart] = function()
if room:getTag("FirstRound") then
room:setTag("FirstRound", false)
end
room:setTag("RoundCount", room:getTag("RoundCount") + 1)
room:doBroadcastNotify("UpdateRoundNum", room:getTag("RoundCount"))
for _, p in ipairs(room.players) do
p:setCardUseHistory("", 0, Player.HistoryRound)
p:setSkillUseHistory("", 0, Player.HistoryRound)
for name, _ in pairs(p.mark) do
if name:endsWith("-round") then
room:setPlayerMark(p, name, 0)
end
end
end
room:sendLog{ type = "$AppendSeparator" }
end,
[fk.EventPhaseProceeding] = function()
switch(player.phase, {
[Player.PhaseNone] = function()
error("You should never proceed PhaseNone")
end,
[Player.RoundStart] = function()
end,
[Player.Start] = function()
end,
[Player.Judge] = function()
local cards = player:getCardIds(Player.Judge)
for i = #cards, 1, -1 do
local card
card = player:removeVirtualEquip(cards[i])
if not card then
card = Fk:getCardById(cards[i])
end
room:moveCardTo(card, Card.Processing, nil, fk.ReasonPut, self.name)
---@type CardEffectEvent
local effect_data = {
card = card,
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()
local data = {
n = 2
}
room.logic:trigger(fk.DrawNCards, player, data)
room:drawCards(player, data.n, self.name)
room.logic:trigger(fk.AfterDrawNCards, player, data)
end,
[Player.Play] = function()
while not player.dead do
room:notifyMoveFocus(player, "PlayCard")
local result = room:doRequest(player, "PlayCard", player.id)
if result == "" then break end
local use = room:handleUseCardReply(player, result)
if use then
room:useCard(use)
end
end
end,
[Player.Discard] = function()
local discardNum = #player:getCardIds(Player.Hand) - player:getMaxCards()
if discardNum > 0 then
room:askForDiscard(player, discardNum, discardNum, false, self.name)
end
end,
[Player.Finish] = function()
end,
[Player.NotActive] = function()
end,
})
end,
[fk.EventPhaseEnd] = function()
if player.phase == Player.Play then
for _, p in ipairs(room.players) do
p:setCardUseHistory("", 0, Player.HistoryPhase)
p:setSkillUseHistory("", 0, Player.HistoryPhase)
for name, _ in pairs(p.mark) do
if name:endsWith("-phase") then
room:setPlayerMark(p, name, 0)
end
end
end
end
end,
[fk.EventPhaseChanging] = function()
-- TODO: copy but dont copy all
if data.to == Player.NotActive then
for _, p in ipairs(room.players) do
p:setCardUseHistory("", 0, Player.HistoryTurn)
p:setSkillUseHistory("", 0, Player.HistoryTurn)
for name, _ in pairs(p.mark) do
if name:endsWith("-turn") then
room:setPlayerMark(p, name, 0)
end
end
end
end
end,
[fk.AskForPeaches] = function() [fk.AskForPeaches] = function()
local dyingPlayer = room:getPlayerById(data.who) local dyingPlayer = room:getPlayerById(data.who)
while dyingPlayer.hp < 1 do while dyingPlayer.hp < 1 do

View File

@ -125,8 +125,11 @@ local test_vs = fk.CreateViewAsSkill{
} }
local test_trig = fk.CreateTriggerSkill{ local test_trig = fk.CreateTriggerSkill{
name = "test_trig", name = "test_trig",
events = {fk.TurnStart}, events = {fk.Damage},
can_trigger = function() p("a") end, on_use = function(self, event, target, player, data)
player:drawCards(1, self.name)
player.room.logic:breakTurn()
end,
} }
local test2 = General(extension, "mouxusheng", "wu", 4, 4, General.Female) local test2 = General(extension, "mouxusheng", "wu", 4, 4, General.Female)
test2.shield = 4 test2.shield = 4