FreeKill/lua/core/engine.lua
notify c6d883eccf Standard skills (#48)
* huatuo

* biyue

* gender of player

* let tablepile smaller

* card emotions

* remove getOtherPlayers

* guicai

* skill audio

* card audio

* death audio

* bgm

* damage sound

* local bgm

* add more skill audio

* android: dont link to quickcontrol2

* android: fix ifndef

* yield only when need

* modify cpp according to clazy

* reduce malloc times

* revert yield

* qingguo

* fix back to lobby

* use compact json in cpp

* notifySkillInvoke animation

* util: string2json

* losehp; tablepile fix

* judge result animation

* add scrollbar for logedit

* add lock on waitForReply

* fix: virtual jink has no effect

* tiandu

* fix: duplicated cards when related to equiparea

* ui: disable okcancel when replying

* ui: disable invaild card when responding

* game: skill & card use history

* game: more judge on vsskill's canUse

* luoyi

* login page i18n

* i18n for server error message

* tuxi

* expand equip area when needed

* add footnote to cards from pile

* ui: only filter CanUseCard when playing

* expand equip when responding

* prompt

* prompt for askforchoice

* guanxing

* fix guanxing

* tieqi

* liuli

* doc for trigger skill

* xiaoji

* lianying

* fanjian

* rende

* add skill's subclass

* TODO: add tmd skill functions for other cards

* paoxiao

* qicai

* guose

* yiji (WIP)
2023-01-29 18:11:41 +08:00

249 lines
6.0 KiB
Lua

---@class Engine : Object
---@field packages table<string, Package>
---@field package_names string[]
---@field skills table<string, Skill>
---@field related_skills table<string, Skill[]>
---@field global_trigger TriggerSkill[]
---@field global_status_skill table<class, Skill[]>
---@field generals table<string, General>
---@field lords string[]
---@field cards Card[]
---@field translations table<string, string>
local Engine = class("Engine")
function Engine:initialize()
-- Engine should be singleton
if Fk ~= nil then
error("Engine has been initialized")
return
end
Fk = self
self.packages = {} -- name --> Package
self.package_names = {}
self.skills = {} -- name --> Skill
self.related_skills = {} -- skillName --> relatedSkill[]
self.global_trigger = {}
self.global_status_skill = {}
self.generals = {} -- name --> General
self.lords = {} -- lordName[]
self.cards = {} -- Card[]
self.translations = {} -- srcText --> translated
self:loadPackages()
self:addSkills(AuxSkills)
end
---@param pack Package
function Engine:loadPackage(pack)
assert(pack:isInstanceOf(Package))
if self.packages[pack.name] ~= nil then
error(string.format("Duplicate package %s detected", pack.name))
end
self.packages[pack.name] = pack
table.insert(self.package_names, pack.name)
-- add cards, generals and skills to Engine
if pack.type == Package.CardPack then
self:addCards(pack.cards)
elseif pack.type == Package.GeneralPack then
self:addGenerals(pack.generals)
end
self:addSkills(pack:getSkills())
end
function Engine:loadPackages()
local directories = FileIO.ls("packages")
-- load standard & standard_cards first
self:loadPackage(require("packages.standard"))
self:loadPackage(require("packages.standard_cards"))
table.removeOne(directories, "standard")
table.removeOne(directories, "standard_cards")
for _, dir in ipairs(directories) do
if FileIO.isDir("packages/" .. dir) then
local pack = require(string.format("packages.%s", dir))
-- Note that instance of Package is a table too
-- so dont use type(pack) == "table" here
if pack[1] ~= nil then
for _, p in ipairs(pack) do
self:loadPackage(p)
end
else
self:loadPackage(pack)
end
end
end
end
---@param t table
function Engine:loadTranslationTable(t)
assert(type(t) == "table")
for k, v in pairs(t) do
self.translations[k] = v
end
end
function Engine:translate(src)
local ret = self.translations[src]
if not ret then return src end
return ret
end
---@param skill Skill
function Engine:addSkill(skill)
assert(skill.class:isSubclassOf(Skill))
if self.skills[skill.name] ~= nil then
error(string.format("Duplicate skill %s detected", skill.name))
end
self.skills[skill.name] = skill
if skill.global then
if skill:isInstanceOf(TriggerSkill) then
table.insert(self.global_trigger, skill)
else
local t = self.global_status_skill
t[skill.class] = t[skill.class] or {}
table.insert(t[skill.class], skill)
end
end
for _, s in ipairs(skill.related_skills) do
self:addSkill(s)
end
end
---@param skills Skill[]
function Engine:addSkills(skills)
assert(type(skills) == "table")
for _, skill in ipairs(skills) do
self:addSkill(skill)
end
end
---@param general General
function Engine:addGeneral(general)
assert(general:isInstanceOf(General))
if self.generals[general.name] ~= nil then
error(string.format("Duplicate general %s detected", general.name))
end
self.generals[general.name] = general
end
---@param generals General[]
function Engine:addGenerals(generals)
assert(type(generals) == "table")
for _, general in ipairs(generals) do
self:addGeneral(general)
end
end
local cardId = 1
local _card_name_table = {}
---@param card Card
function Engine:addCard(card)
assert(card.class:isSubclassOf(Card))
card.id = cardId
cardId = cardId + 1
table.insert(self.cards, card)
_card_name_table[card.name] = card
end
---@param cards Card[]
function Engine:addCards(cards)
for _, card in ipairs(cards) do
self:addCard(card)
end
end
---@param name string
---@param suit Suit
---@param number integer
---@return Card
function Engine:cloneCard(name, suit, number)
local cd = _card_name_table[name]
assert(cd, "Attempt to clone a card that not added to engine")
return cd:clone(suit, number)
end
---@param num integer
---@param generalPool General[]
---@param except string[]
---@param filter function
---@return General[]
function Engine:getGeneralsRandomly(num, generalPool, except, filter)
if filter then
assert(type(filter) == "function")
end
generalPool = generalPool or self.generals
except = except or {}
local availableGenerals = {}
for _, general in pairs(generalPool) do
if not table.contains(except, general.name) and not (filter and filter(general)) then
table.insert(availableGenerals, general)
end
end
if #availableGenerals == 0 then
return {}
end
local result = {}
for i = 1, num do
local randomGeneral = math.random(1, #availableGenerals)
table.insert(result, availableGenerals[randomGeneral])
table.remove(availableGenerals, randomGeneral)
if #availableGenerals == 0 then
break
end
end
return result
end
---@param except General[]
---@return General[]
function Engine:getAllGenerals(except)
local result = {}
for _, general in ipairs(self.generals) do
if not (except and table.contains(except, general)) then
table.insert(result, general)
end
end
return result
end
---@param except integer[]
---@return integer[]
function Engine:getAllCardIds(except)
local result = {}
for _, card in ipairs(self.cards) do
if not (except and table.contains(except, card.id)) then
table.insert(result, card.id)
end
end
return result
end
---@param id integer
---@return Card
function Engine:getCardById(id)
return self.cards[id]
end
function Engine:currentRoom()
if ClientInstance then
return ClientInstance
end
return RoomInstance
end
return Engine