360 lines
11 KiB
Lua
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
|