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 except string[]
---@param filter function
---@return General[] generals
---@return General[]
function Engine:getGeneralsRandomly(num, generalPool, except, filter)
if filter then
assert(type(filter) == "function")

View File

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

View File

@ -13,6 +13,9 @@
---@field dead boolean
---@field state string
---@field player_skills Skill[]
---@field flag string[]
---@field tag table<string, any>
---@field mark table<string, integer>
local Player = class("Player")
---@alias Phase integer
@ -43,6 +46,9 @@ function Player:initialize()
self.state = ""
self.player_skills = {}
self.flag = {}
self.tag = {}
self.mark = {}
end
---@param general General
@ -56,8 +62,65 @@ function Player:setGeneral(general, setHp, addSkills)
end
if addSkills then
table.insertTable(self.playerSkills, general.skills)
table.insertTable(self.player_skills, general.skills)
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

View File

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

View File

@ -71,7 +71,7 @@ Sql = {
--- Execute a `SELECT` SQL statement.
---@param db fk.SQLite3
---@param sql string
---@return table data # { [columnName] --> result : string[] }
---@return table @ { [columnName] --> result : string[] }
exec_select = function(db, sql)
return json.decode(fk.SelectFromDb(db, sql))
end,
@ -127,3 +127,10 @@ function CreateEnum(table, enum)
print(string.format(enum_format, table, v, i))
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"
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
function fk.CreateBasicCard(spec)
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
@ -21,7 +36,7 @@ function fk.CreateBasicCard(spec)
return card
end
---@param spec table
---@param spec CardSpec
---@return TrickCard
function fk.CreateTrickCard(spec)
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
@ -34,7 +49,7 @@ function fk.CreateTrickCard(spec)
return card
end
---@param spec table
---@param spec CardSpec
---@return EquipCard
function fk.CreateEquipCard(spec)
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
@ -47,7 +62,7 @@ function fk.CreateEquipCard(spec)
return card
end
---@param spec table
---@param spec TriggerSkillSpec
---@return TriggerSkill
function fk.CreateTriggerSkill(spec)
assert(type(spec.name) == "string")
@ -81,6 +96,10 @@ function fk.CreateTriggerSkill(spec)
skill.canRefresh = spec.can_refresh
end
if spec.on_refresh then
skill.refresh = spec.on_refresh
end
if not spec.priority then
if frequency == Skill.Wake then
spec.priority = 3
@ -91,7 +110,7 @@ function fk.CreateTriggerSkill(spec)
end
end
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
end
elseif type(spec.priority) == "table" then

View File

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

View File

@ -49,8 +49,8 @@ end
--- Wait for at most *timeout* seconds for reply from client.
---
--- If *timeout* is negative or **nil**, the function will wait forever until get reply.
---@param timeout integer # seconds to wait
---@return string reply # JSON data
---@param timeout integer @ seconds to wait
---@return string @ JSON data
function ServerPlayer:waitForReply(timeout)
local result = ""
if timeout == nil then
@ -85,4 +85,12 @@ function ServerPlayer:getNextAlive()
return ret
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

View File

@ -41,6 +41,6 @@ json = {}
function json.encode(obj)end
--- convert JSON string to lua types
---@param str string # JSON string to decode
---@param str string @ JSON string to decode
---@return table|number|string
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.
---
--- If *timeout* is negative or **nil**, the function will wait forever until get reply.
---@param timeout integer # seconds to wait
---@return string reply # JSON data
---@param timeout integer @ seconds to wait
---@return string @ JSON data
---@overload fun()
function FServerPlayer:waitForReply(timeout)end

View File

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

View File

@ -11,11 +11,41 @@ GameRule = fk.CreateTriggerSkill{
end,
on_trigger = function(self, event, target, player, data)
if player == nil then return false end
local room = player.room
if player.room:askForSkillInvoke(player, self.name) then
-- do something
if RoomInstance.tag["SkipGameRule"] then
RoomInstance.tag["SkipGameRule"] = false
return false
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
end,

View File

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

View File

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

View File

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