FreeKill/lua/lib/fkparser.lua
2023-02-26 16:51:29 +08:00

360 lines
11 KiB
Lua

-- FreeKill's fkparse interface
-- fkparse (FreeKill parser), a game code generator
-- For license information, check generated lua files.
-- In most cases, fk's basic modules are loaded before extension calls
-- "require 'fkparser'", so we needn't to import lua modules here.
local string2suit = {
spade = Card.Spade,
club = Card.Club,
heart = Card.Heart,
diamond = Card.Diamond,
no_suit = Card.NoSuit,
no_suit_black = Card.NoSuitBlack,
no_suit_red = Card.NoSuitRed,
}
local fkp = { functions = {} }
fkp.functions.prepend = function(arr, e) table.insert(arr, 1, e) end
fkp.functions.append = function(arr, e) table.insert(arr, e) end
fkp.functions.drawCards = function(p, n) p:drawCards(n) end
fkp.functions.loseHp = function(p, n) p.room:loseHp(p, n) end
fkp.functions.loseMaxHp = function(p, n) p.room:changeMaxHp(p, -n) end
fkp.functions.damage = function(from, to, n, nature, card, reason)
local damage = {}
damage.from = from
damage.to = to
damage.damage = n
damage.damageType = nature
damage.card = card
damage.skillName = reason
to.room:damage(damage)
end
fkp.functions.recover = function(player, int, who, card)
local recover = {}
recover.who = player
recover.num = int
recover.recoverBy = who
recover.card = card
player.room:recover(recover)
end
fkp.functions.recoverMaxHp = function(p, n) p.room:changeMaxHp(p, n) end
fkp.functions.acquireSkill = function(player, skill)
player.room:handleAddLoseSkills(player, skill)
end
fkp.functions.loseSkill = function(player, skill)
player.room:handleAddLoseSkills(player, "-" .. skill)
end
fkp.functions.addMark = function(player, mark, count, hidden)
local room = player.room
if hidden then
mark = string.gsub(mark, "@", "_")
end
room:addPlayerMark(player, mark, count)
end
fkp.functions.loseMark = function(player, mark, count, hidden)
local room = player.room
if hidden then
mark = string.gsub(mark, "@", "_")
end
room:removePlayerMark(player, mark, count)
end
fkp.functions.getMark = function(player, mark, hidden)
if hidden then
mark = string.gsub(mark, "@", "_")
end
return player:getMark(mark)
end
fkp.functions.judge = function(player, reason, pattern, good, play_animation)
local judge = {}
judge.who = player
judge.reason = reason
judge.pattern = pattern
-- judge.good = good
-- judge.play_animation = play_animation
player.room:judge(judge)
return judge.card
end
fkp.functions.retrial = function(card, player, judge, skill_name, exchange)
local room = player.room
return room:retrial(card, player, judge, skill_name, exchange)
end
fkp.functions.hasSkill = function(p, s) return p:hasSkill(s) end
fkp.functions.turnOver = function(p) p:turnOver() end
fkp.functions.distanceTo = function(p1, p2) return p1:distanceTo(p2) end
fkp.functions.getCards = function(p, area)
return table.map(p:getCardIds(area), function(id) return Fk:getCardById(id) end)
end
-- interactive methods
fkp.functions.buildPrompt = function(base, src, dest, arg, arg2)
if src == nil then
src = ""
else
src = src.id
end
if dest == nil then
dest = ""
else
dest = dest.id
end
if arg == nil then arg = "" end
if arg2 == nil then arg2 = "" end
local prompt_tab = {src, dest, arg, arg2}
if arg2 == "" then
table.remove(prompt_tab, 4)
if arg == "" then
table.remove(prompt_tab, 3)
if dest == "" then
table.remove(prompt_tab, 2)
if src == "" then
table.remove(prompt_tab, 1)
end
end
end
end
for _, str in ipairs(prompt_tab) do
base = base .. ":" .. str
end
return base
end
fkp.functions.askForChoice = function(player, choices, reason)
return player.room:askForChoice(player, choices, reason)
end
fkp.functions.askForPlayerChosen = function(player, targets, reason, prompt, optional, notify)
return player.room:askForChoosePlayers(player, targets, 1, 1, prompt, reason)
end
fkp.functions.askForSkillInvoke = function(player, skill)
return player:askForSkillInvoke(skill)
end
fkp.functions.askRespondForCard = function(player, pattern, prompt, isRetrial, skill_name)
return player.room:askForResponse(player, skill_name, pattern, prompt, true)
end
-- skill prototypes
--------------------------------------------
fkp.CreateTriggerSkill = function(spec)
local eve = {}
local refresh_eve = {}
local specs = spec.specs
local re_specs = spec.refresh_specs
for event, _ in pairs(specs) do
table.insert(eve, event)
end
for event, _ in pairs(re_specs) do
table.insert(refresh_eve, event)
end
return fk.CreateTriggerSkill{
name = spec.name,
frequency = spec.frequency or Skill.NotFrequent,
events = eve,
can_trigger = function(self, event, target, player, data)
local func = specs[event] and specs[event][1] or nil
if not func then
return TriggerSkill.triggerable(self, event, target, player, data)
end
return func(self, target, player, data)
end,
on_trigger = function(self, event, target, player, data)
local func = specs[event] and specs[event][4] or nil
if not func then
return TriggerSkill.trigger(self, event, target, player, data)
end
return func(self, target, player, data)
end,
on_cost = function(self, event, target, player, data)
local func = specs[event] and specs[event][3] or nil
if not func then
return TriggerSkill.cost(self, event, target, player, data)
end
return func(self, target, player, data)
end,
on_use = function(self, event, target, player, data)
local func = specs[event] and specs[event][2] or nil
if not func then
return TriggerSkill.use(self, event, target, player, data)
end
return func(self, target, player, data)
end,
refresh_events = refresh_eve,
can_refresh = function(self, event, target, player, data)
local func = re_specs[event] and re_specs[event][1] or nil
if not func then
return TriggerSkill.canRefresh(self, event, target, player, data)
end
return func(self, target, player, data)
end,
on_refresh = function(self, event, target, player, data)
local func = re_specs[event] and re_specs[event][2] or nil
if not func then
return TriggerSkill.refresh(self, event, target, player, data)
end
return func(self, target, player, data)
end,
}
end
fkp.CreateActiveSkill = function(spec)
return fk.CreateActiveSkill{
name = spec.name,
can_use = spec.can_use,
card_filter = function(self, to_select, selected)
local card = Fk:getCardById(to_select)
local clist = {}
for _, id in ipairs(selected) do
table.insert(clist, Fk:getCardById(id))
end
return spec.card_filter(self, clist, card)
end,
target_filter = function(self, to_select, selected, cards)
local room = Fk:currentRoom()
local target = room:getPlayerById(to_select)
local plist = {}
for _, id in ipairs(selected) do
table.insert(plist, room:getPlayerById(id))
end
local clist = {}
for _, id in ipairs(cards) do
table.insert(clist, Fk:getCardById(id))
end
return spec.target_filter(self, plist, target, clist)
end,
feasible = function(self, targets, cards)
local room = Fk:currentRoom()
local plist = {}
for _, id in ipairs(targets) do
table.insert(plist, room:getPlayerById(id))
end
local clist = {}
for _, id in ipairs(cards) do
table.insert(clist, Fk:getCardById(id))
end
return spec.feasible(self, plist, clist)
end,
on_use = function(self, room, use)
local cards = use.cards
local from = use.from
local targets = use.tos
local source = room:getPlayerById(from)
local plist = {}
for _, id in ipairs(targets) do
table.insert(plist, room:getPlayerById(id))
end
local clist = {}
for _, id in ipairs(cards) do
table.insert(clist, Fk:getCardById(id))
end
return spec.on_use(self, source, plist, clist)
end,
on_effect = function(self, room, effect)
-- TODO: active skill for card!
end,
}
end
fkp.functions.newVirtualCard = function(number, suit, name, subcards, skill)
subcards = subcards or {}
local ret = Fk:cloneCard(name, string2suit[suit], number)
if not ret then
ret = Fk:cloneCard("slash", string2suit[suit], number)
end
ret.skillName = skill
ret:addSubcards(subcards)
return ret
end
fkp.functions.buildPattern = function(names, suits, numbers)
if not names then names = {"."} end
if not suits then suits = {"."} end
if not numbers then numbers = {"."} end
names = table.concat(names, ",")
suits = table.concat(suits, ",")
numbers = table.concat(numbers, ",")
return string.format("%s|%s|%s", names, numbers, suits)
end
fkp.CreateViewAsSkill = function(spec)
return fk.CreateViewAsSkill{
name = spec.name,
card_filter = function(self, to_select, selected)
local card = Fk:getCardById(to_select)
local clist = {}
for _, id in ipairs(selected) do
table.insert(clist, Fk:getCardById(id))
end
return spec.card_filter(self, clist, card)
end,
view_as = function(self, cards)
local clist = {}
for _, c in ipairs(cards) do
table.insert(clist, Fk:getCardById(c))
end
if spec.feasible(self, clist) then
return spec.view_as(self, clist)
end
return nil
end,
enabled_at_play = spec.can_use,
enabled_at_response = spec.can_response,
pattern = table.concat(spec.response_patterns, ";"),
}
end
fkp.CreateTargetModSkill = function(_spec)
local spec = { name = _spec.name }
local function getVCardFromActiveSkill(skill)
if not string.find(skill.name, "_skill") then return 0 end
local str = string.gsub(skill.name, "_skill", "")
return Fk:cloneCard(str)
end
if _spec.residue_func then
spec.residue_func = function(self, target, skill, scope, card)
return _spec.residue_func(self, target, card or getVCardFromActiveSkill(skill))
end
end
if _spec.distance_limit_func then
spec.distance_limit_func = function(self, target, skill, card)
return _spec.distance_limit_func(self, target, card or getVCardFromActiveSkill(skill))
end
end
if _spec.extra_target_func then
spec.extra_target_func = function(self, target, skill, card)
return _spec.extra_target_func(self, target, card or getVCardFromActiveSkill(skill))
end
end
return fk.CreateTargetModSkill(spec)
end
fkp.CreateFilterSkill = fk.CreateFilterSkill
fkp.CreateProhibitSkill = fk.CreateProhibitSkill
fkp.CreateDistanceSkill = fk.CreateDistanceSkill
fkp.CreateMaxCardsSkill = fk.CreateMaxCardsSkill
fkp.CreateAttackRangeSkill = fk.CreateAttackRangeSkill
return fkp