gamerule:Turnstart (#12)

* add tag to room

* add switch statement(util.lua)

* using emmylua

* gamerule(..)

* turnOver

* add many events

* stop the room when deleting

Co-authored-by: Notify-ctrl <notify-ctrl@qq.com>
This commit is contained in:
Notify-ctrl 2022-04-02 21:39:44 +08:00 committed by GitHub
parent 8637356a04
commit 927c5f479b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 213 additions and 54 deletions

View File

@ -117,7 +117,7 @@ end
---@param generalPool General[] ---@param generalPool General[]
---@param except string[] ---@param except string[]
---@param filter function ---@param filter function
---@return General[] generals ---@return General[]
function Engine:getGeneralsRandomly(num, generalPool, except, filter) function Engine:getGeneralsRandomly(num, generalPool, except, filter)
if filter then if filter then
assert(type(filter) == "function") assert(type(filter) == "function")

View File

@ -25,7 +25,7 @@ function Package:initialize(name, _type)
self.cards = {} self.cards = {}
end end
---@return table skills ---@return Skill[]
function Package:getSkills() function Package:getSkills()
local ret = {table.unpack(self.related_skills)} local ret = {table.unpack(self.related_skills)}
if self.type == Package.GeneralPack then if self.type == Package.GeneralPack then

View File

@ -13,6 +13,9 @@
---@field dead boolean ---@field dead boolean
---@field state string ---@field state string
---@field player_skills Skill[] ---@field player_skills Skill[]
---@field flag string[]
---@field tag table<string, any>
---@field mark table<string, integer>
local Player = class("Player") local Player = class("Player")
---@alias Phase integer ---@alias Phase integer
@ -43,6 +46,9 @@ function Player:initialize()
self.state = "" self.state = ""
self.player_skills = {} self.player_skills = {}
self.flag = {}
self.tag = {}
self.mark = {}
end end
---@param general General ---@param general General
@ -56,8 +62,65 @@ function Player:setGeneral(general, setHp, addSkills)
end end
if addSkills then if addSkills then
table.insertTable(self.playerSkills, general.skills) table.insertTable(self.player_skills, general.skills)
end end
end end
---@param flag string
function Player:hasFlag(flag)
return table.contains(self.flag, flag)
end
---@param flag string
function Player:setFlag(flag)
if flag == "." then
self:clearFlags()
return
end
if flag:sub(1, 1) == "-" then
flag = flag:sub(2, #flag)
table.removeOne(self.flag, flag)
return
end
if not self:hasFlag(flag) then
table.insert(self.flag, flag)
end
end
function Player:clearFlags()
self.flag = {}
end
function Player:addMark(mark, count)
count = count or 1
local num = self.mark[mark]
num = num or 0
self:setMark(mark, math.max(num + count, 0))
end
function Player:removeMark(mark, count)
count = count or 1
local num = self.mark[mark]
num = num or 0
self:setMark(mark, math.max(num - count, 0))
end
function Player:setMark(mark, count)
if self.mark[mark] ~= count then
self.mark[mark] = count
end
end
function Player:getMark(mark)
return (self.mark[mark] or 0)
end
function Player:getMarkNames()
local ret = {}
for k, _ in pairs(self.mark) do
table.insert(ret, k)
end
return ret
end
return Player return Player

View File

@ -17,25 +17,24 @@ end
-- Default functions -- Default functions
---Determine whether a skill can refresh at this moment ---Determine whether a skill can refresh at this moment
---@param event Event # TriggerEvent ---@param event Event @ TriggerEvent
---@param target ServerPlayer # Player who triggered this event ---@param target ServerPlayer @ Player who triggered this event
---@param player ServerPlayer # Player who is operating ---@param player ServerPlayer @ Player who is operating
---@param data any # useful data of the event ---@param data any @ useful data of the event
---@return nil
function TriggerSkill:canRefresh(event, target, player, data) return false end function TriggerSkill:canRefresh(event, target, player, data) return false end
---Refresh the skill (e.g. clear marks) ---Refresh the skill (e.g. clear marks)
---@param event Event # TriggerEvent ---@param event Event @ TriggerEvent
---@param target ServerPlayer # Player who triggered this event ---@param target ServerPlayer @ Player who triggered this event
---@param player ServerPlayer # Player who is operating ---@param player ServerPlayer @ Player who is operating
---@param data any # useful data of the event ---@param data any @ useful data of the event
function TriggerSkill:refresh(event, target, player, data) end function TriggerSkill:refresh(event, target, player, data) end
---Determine whether a skill can trigger at this moment ---Determine whether a skill can trigger at this moment
---@param event Event # TriggerEvent ---@param event Event @ TriggerEvent
---@param target ServerPlayer # Player who triggered this event ---@param target ServerPlayer @ Player who triggered this event
---@param player ServerPlayer # Player who is operating ---@param player ServerPlayer @ Player who is operating
---@param data any # useful data of the event ---@param data any @ useful data of the event
---@return boolean ---@return boolean
function TriggerSkill:triggerable(event, target, player, data) function TriggerSkill:triggerable(event, target, player, data)
return target and (target == player) return target and (target == player)
@ -43,11 +42,11 @@ function TriggerSkill:triggerable(event, target, player, data)
end end
---Trigger this skill ---Trigger this skill
---@param event Event # TriggerEvent ---@param event Event @ TriggerEvent
---@param target ServerPlayer # Player who triggered this event ---@param target ServerPlayer @ Player who triggered this event
---@param player ServerPlayer # Player who is operating ---@param player ServerPlayer @ Player who is operating
---@param data any # useful data of the event ---@param data any @ useful data of the event
---@return boolean # returns true if trigger is broken ---@return boolean @ returns true if trigger is broken
function TriggerSkill:trigger(event, target, player, data) function TriggerSkill:trigger(event, target, player, data)
if player.room:askForSkillInvoke(player, self.name) then if player.room:askForSkillInvoke(player, self.name) then
return self:use(event, target, player, data) return self:use(event, target, player, data)
@ -56,10 +55,10 @@ function TriggerSkill:trigger(event, target, player, data)
end end
---Use this skill ---Use this skill
---@param event Event # TriggerEvent ---@param event Event @ TriggerEvent
---@param target ServerPlayer # Player who triggered this event ---@param target ServerPlayer @ Player who triggered this event
---@param player ServerPlayer # Player who is operating ---@param player ServerPlayer @ Player who is operating
---@param data any # useful data of the event ---@param data any @ useful data of the event
---@return boolean ---@return boolean
function TriggerSkill:use(event, target, player, data) end function TriggerSkill:use(event, target, player, data) end

View File

@ -71,7 +71,7 @@ Sql = {
--- Execute a `SELECT` SQL statement. --- Execute a `SELECT` SQL statement.
---@param db fk.SQLite3 ---@param db fk.SQLite3
---@param sql string ---@param sql string
---@return table data # { [columnName] --> result : string[] } ---@return table @ { [columnName] --> result : string[] }
exec_select = function(db, sql) exec_select = function(db, sql)
return json.decode(fk.SelectFromDb(db, sql)) return json.decode(fk.SelectFromDb(db, sql))
end, end,
@ -127,3 +127,10 @@ function CreateEnum(table, enum)
print(string.format(enum_format, table, v, i)) print(string.format(enum_format, table, v, i))
end end
end end
function switch(param, case_table)
local case = case_table[param]
if case then return case() end
local def = case_table["default"]
return def and def() or nil
end

View File

@ -8,7 +8,22 @@ EquipCard = require "core.card_type.equip"
dofile "lua/server/event.lua" dofile "lua/server/event.lua"
TriggerSkill = require "core.skill_type.trigger" TriggerSkill = require "core.skill_type.trigger"
---@param spec table ---@class CardSpec: Card
---@class SkillSpec: Skill
---@alias TrigFunc fun(self: TriggerSkill, event: Event, target: ServerPlayer, player: ServerPlayer):boolean
---@class TriggerSkillSpec: SkillSpec
---@field global boolean
---@field events Event | Event[]
---@field refresh_events Event | Event[]
---@field priority number | table<Event, number>
---@field on_trigger TrigFunc
---@field can_trigger TrigFunc
---@field on_refresh TrigFunc
---@field can_refresh TrigFunc
---@param spec CardSpec
---@return BasicCard ---@return BasicCard
function fk.CreateBasicCard(spec) function fk.CreateBasicCard(spec)
assert(type(spec.name) == "string" or type(spec.class_name) == "string") assert(type(spec.name) == "string" or type(spec.class_name) == "string")
@ -21,7 +36,7 @@ function fk.CreateBasicCard(spec)
return card return card
end end
---@param spec table ---@param spec CardSpec
---@return TrickCard ---@return TrickCard
function fk.CreateTrickCard(spec) function fk.CreateTrickCard(spec)
assert(type(spec.name) == "string" or type(spec.class_name) == "string") assert(type(spec.name) == "string" or type(spec.class_name) == "string")
@ -34,7 +49,7 @@ function fk.CreateTrickCard(spec)
return card return card
end end
---@param spec table ---@param spec CardSpec
---@return EquipCard ---@return EquipCard
function fk.CreateEquipCard(spec) function fk.CreateEquipCard(spec)
assert(type(spec.name) == "string" or type(spec.class_name) == "string") assert(type(spec.name) == "string" or type(spec.class_name) == "string")
@ -47,7 +62,7 @@ function fk.CreateEquipCard(spec)
return card return card
end end
---@param spec table ---@param spec TriggerSkillSpec
---@return TriggerSkill ---@return TriggerSkill
function fk.CreateTriggerSkill(spec) function fk.CreateTriggerSkill(spec)
assert(type(spec.name) == "string") assert(type(spec.name) == "string")
@ -81,6 +96,10 @@ function fk.CreateTriggerSkill(spec)
skill.canRefresh = spec.can_refresh skill.canRefresh = spec.can_refresh
end end
if spec.on_refresh then
skill.refresh = spec.on_refresh
end
if not spec.priority then if not spec.priority then
if frequency == Skill.Wake then if frequency == Skill.Wake then
spec.priority = 3 spec.priority = 3
@ -91,7 +110,7 @@ function fk.CreateTriggerSkill(spec)
end end
end end
if type(spec.priority) == "number" then if type(spec.priority) == "number" then
for _, event in ipairs(spec.events) do for _, event in ipairs(skill.events) do
skill.priority_table[event] = spec.priority skill.priority_table[event] = spec.priority
end end
elseif type(spec.priority) == "table" then elseif type(spec.priority) == "table" then

View File

@ -8,4 +8,31 @@ fk.EventPhaseProceeding = 5
fk.EventPhaseEnd = 6 fk.EventPhaseEnd = 6
fk.EventPhaseChanging = 7 fk.EventPhaseChanging = 7
fk.EventPhaseSkipping = 8 fk.EventPhaseSkipping = 8
fk.NumOfEvents = 9
fk.DrawNCards = 9
fk.AfterDrawNCards = 10
fk.DrawInitialCards = 11
fk.AfterDrawInitialCards = 12
fk.PreHpRecover = 13
fk.HpRecover = 14
fk.PreHpLost = 15
fk.HpLost = 16
fk.HpChanged = 17
fk.MaxHpChanged = 18
fk.EventLoseSkill = 19
fk.EventAcquireSkill = 20
fk.StartJudge = 21
fk.AskForRetrial = 22
fk.FinishRetrial = 23
fk.FinishJudge = 24
fk.PindianVerifying = 25
fk.Pindian = 26
fk.TurnedOver = 27
fk.ChainStateChanged = 28
fk.NumOfEvents = 29

View File

@ -5,6 +5,7 @@
---@field current ServerPlayer ---@field current ServerPlayer
---@field game_finished boolean ---@field game_finished boolean
---@field timeout integer ---@field timeout integer
---@field tag table<string, any>
local Room = class("Room") local Room = class("Room")
-- load classes used by the game -- load classes used by the game
@ -34,6 +35,7 @@ function Room:initialize(_room)
self.current = nil self.current = nil
self.game_finished = false self.game_finished = false
self.timeout = _room:getTimeout() self.timeout = _room:getTimeout()
self.tag = {}
end end
-- When this function returns, the Room(C++) thread stopped. -- When this function returns, the Room(C++) thread stopped.
@ -70,7 +72,7 @@ end
---@param command string ---@param command string
---@param jsonData string ---@param jsonData string
---@param players ServerPlayer[] # default all players ---@param players ServerPlayer[] @ default all players
function Room:doBroadcastNotify(command, jsonData, players) function Room:doBroadcastNotify(command, jsonData, players)
players = players or self.players players = players or self.players
local tolist = fk.SPlayerList() local tolist = fk.SPlayerList()
@ -83,7 +85,7 @@ end
---@param player ServerPlayer ---@param player ServerPlayer
---@param command string ---@param command string
---@param jsonData string ---@param jsonData string
---@param wait boolean # default true ---@param wait boolean @ default true
---@return string | nil ---@return string | nil
function Room:doRequest(player, command, jsonData, wait) function Room:doRequest(player, command, jsonData, wait)
if wait == nil then wait = true end if wait == nil then wait = true end

View File

@ -49,8 +49,8 @@ end
--- Wait for at most *timeout* seconds for reply from client. --- Wait for at most *timeout* seconds for reply from client.
--- ---
--- If *timeout* is negative or **nil**, the function will wait forever until get reply. --- If *timeout* is negative or **nil**, the function will wait forever until get reply.
---@param timeout integer # seconds to wait ---@param timeout integer @ seconds to wait
---@return string reply # JSON data ---@return string @ JSON data
function ServerPlayer:waitForReply(timeout) function ServerPlayer:waitForReply(timeout)
local result = "" local result = ""
if timeout == nil then if timeout == nil then
@ -85,4 +85,12 @@ function ServerPlayer:getNextAlive()
return ret return ret
end end
function ServerPlayer:turnOver()
self.faceup = not self.faceup
self.room:broadcastProperty(self, "faceup")
-- TODO: log
self.room.logic:trigger(fk.TurnedOver, self)
end
return ServerPlayer return ServerPlayer

View File

@ -41,6 +41,6 @@ json = {}
function json.encode(obj)end function json.encode(obj)end
--- convert JSON string to lua types --- convert JSON string to lua types
---@param str string # JSON string to decode ---@param str string @ JSON string to decode
---@return table|number|string ---@return table|number|string
function json.decode(str)end function json.decode(str)end

View File

@ -53,8 +53,8 @@ function FServerPlayer:doRequest(command,jsonData,timeout)end
--- Wait for at most *timeout* seconds for reply from client. --- Wait for at most *timeout* seconds for reply from client.
--- ---
--- If *timeout* is negative or **nil**, the function will wait forever until get reply. --- If *timeout* is negative or **nil**, the function will wait forever until get reply.
---@param timeout integer # seconds to wait ---@param timeout integer @ seconds to wait
---@return string reply # JSON data ---@return string @ JSON data
---@overload fun() ---@overload fun()
function FServerPlayer:waitForReply(timeout)end function FServerPlayer:waitForReply(timeout)end

View File

@ -16,17 +16,17 @@ FRoom = {}
function FServer:createRoom(owner,name,capacity)end function FServer:createRoom(owner,name,capacity)end
---@param id integer ---@param id integer
---@return fk.Room room ---@return fk.Room
function FServer:findRoom(id)end function FServer:findRoom(id)end
---@return fk.Room room ---@return fk.Room
function FServer:lobby()end function FServer:lobby()end
---@param id integer ---@param id integer
---@return fk.ServerPlayer player ---@return fk.ServerPlayer
function FServer:findPlayer(id)end function FServer:findPlayer(id)end
---@return fk.SQLite3 db ---@return fk.SQLite3
function FServer:getDatabase()end function FServer:getDatabase()end
function FRoom:getServer()end function FRoom:getServer()end

View File

@ -11,11 +11,41 @@ GameRule = fk.CreateTriggerSkill{
end, end,
on_trigger = function(self, event, target, player, data) on_trigger = function(self, event, target, player, data)
if player == nil then return false end if RoomInstance.tag["SkipGameRule"] then
local room = player.room RoomInstance.tag["SkipGameRule"] = false
if player.room:askForSkillInvoke(player, self.name) then return false
-- do something
end end
if target == nil then
if event == fk.GameStart then
print("Game started")
RoomInstance.tag["FirstRound"] = true
end
return false
end
local room = player.room
switch(event, {
[fk.TurnStart] = function()
player = room.current
if room.tag["FirstRound"] == true then
room.tag["FirstRound"] = false
player:setFlag("Global_FirstRound")
end
-- TODO: send log
player:addMark("Global_TurnCount")
player:setMark("damage_point_round", 0)
if not player.faceup then
player:setFlag("-Global_FirstRound")
player:turnOver()
elseif not player.dead then
--player:play()
room:askForSkillInvoke(player, "rule")
end
end,
})
return false return false
end, end,

View File

@ -121,7 +121,7 @@ Item {
seatNumber: model.seatNumber seatNumber: model.seatNumber
isDead: model.isDead isDead: model.isDead
dying: model.dying dying: model.dying
faceturned: model.faceturned faceup: model.faceup
chained: model.chained chained: model.chained
drank: model.drank drank: model.drank
isOwner: model.isOwner isOwner: model.isOwner
@ -161,7 +161,7 @@ Item {
self.seatNumber: dashboardModel.seatNumber self.seatNumber: dashboardModel.seatNumber
self.isDead: dashboardModel.isDead self.isDead: dashboardModel.isDead
self.dying: dashboardModel.dying self.dying: dashboardModel.dying
self.faceturned: dashboardModel.faceturned self.faceup: dashboardModel.faceup
self.chained: dashboardModel.chained self.chained: dashboardModel.chained
self.drank: dashboardModel.drank self.drank: dashboardModel.drank
self.isOwner: dashboardModel.isOwner self.isOwner: dashboardModel.isOwner
@ -274,7 +274,7 @@ Item {
seatNumber: 1, seatNumber: 1,
isDead: false, isDead: false,
dying: false, dying: false,
faceturned: false, faceup: true,
chained: false, chained: false,
drank: false, drank: false,
isOwner: false isOwner: false
@ -297,7 +297,7 @@ Item {
seatNumber: i + 1, seatNumber: i + 1,
isDead: false, isDead: false,
dying: false, dying: false,
faceturned: false, faceup: true,
chained: false, chained: false,
drank: false, drank: false,
isOwner: false isOwner: false

View File

@ -20,7 +20,7 @@ Item {
property int seatNumber: 1 property int seatNumber: 1
property bool isDead: false property bool isDead: false
property bool dying: false property bool dying: false
property bool faceturned: false property bool faceup: true
property bool chained: false property bool chained: false
property bool drank: false property bool drank: false
property bool isOwner: false property bool isOwner: false
@ -110,9 +110,9 @@ Item {
Image { Image {
id: turnedOver id: turnedOver
visible: root.faceturned visible: !root.faceup
source: SkinBank.PHOTO_DIR + "faceturned" source: SkinBank.PHOTO_DIR + "faceturned"
anchors.centerIn: photoMask x: 29; y: 5
} }
Image { Image {

View File

@ -30,6 +30,10 @@ Room::Room(Server* server)
Room::~Room() Room::~Room()
{ {
// TODO // TODO
if (isRunning()) {
terminate();
wait();
}
disconnect(); disconnect();
lua_close(L); lua_close(L);
} }