2022-04-01 12:51:01 +00:00
|
|
|
-- load types for extension
|
|
|
|
|
2022-04-30 07:27:56 +00:00
|
|
|
dofile "lua/server/event.lua"
|
|
|
|
dofile "lua/server/system_enum.lua"
|
|
|
|
TriggerSkill = require "core.skill_type.trigger"
|
|
|
|
ActiveSkill = require "core.skill_type.active_skill"
|
2023-01-04 06:21:29 +00:00
|
|
|
DistanceSkill = require "core.skill_type.distance"
|
|
|
|
StatusSkills = {
|
|
|
|
DistanceSkill,
|
|
|
|
}
|
2022-04-30 07:27:56 +00:00
|
|
|
|
2022-04-01 12:51:01 +00:00
|
|
|
BasicCard = require "core.card_type.basic"
|
2022-04-08 10:39:58 +00:00
|
|
|
local Trick = require "core.card_type.trick"
|
|
|
|
TrickCard, DelayedTrickCard = table.unpack(Trick)
|
|
|
|
local Equip = require "core.card_type.equip"
|
|
|
|
_, Weapon, Armor, DefensiveRide, OffensiveRide, Treasure = table.unpack(Equip)
|
2022-04-01 12:51:01 +00:00
|
|
|
|
2022-04-02 13:39:44 +00:00
|
|
|
---@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
|
|
|
|
|
2022-04-30 07:27:56 +00:00
|
|
|
---@param spec TriggerSkillSpec
|
|
|
|
---@return TriggerSkill
|
|
|
|
function fk.CreateTriggerSkill(spec)
|
|
|
|
assert(type(spec.name) == "string")
|
|
|
|
--assert(type(spec.on_trigger) == "function")
|
|
|
|
if spec.frequency then assert(type(spec.frequency) == "number") end
|
|
|
|
|
|
|
|
local frequency = spec.frequency or Skill.NotFrequent
|
|
|
|
local skill = TriggerSkill:new(spec.name, frequency)
|
|
|
|
|
|
|
|
if type(spec.events) == "number" then
|
|
|
|
table.insert(skill.events, spec.events)
|
|
|
|
elseif type(spec.events) == "table" then
|
|
|
|
table.insertTable(skill.events, spec.events)
|
|
|
|
end
|
|
|
|
|
|
|
|
if type(spec.refresh_events) == "number" then
|
|
|
|
table.insert(skill.refresh_events, spec.refresh_events)
|
|
|
|
elseif type(spec.refresh_events) == "table" then
|
|
|
|
table.insertTable(skill.refresh_events, spec.refresh_events)
|
|
|
|
end
|
|
|
|
|
|
|
|
if type(spec.global) == "boolean" then skill.global = spec.global end
|
|
|
|
|
|
|
|
if spec.on_trigger then skill.trigger = spec.on_trigger end
|
|
|
|
|
|
|
|
if spec.can_trigger then
|
|
|
|
skill.triggerable = spec.can_trigger
|
|
|
|
end
|
|
|
|
|
|
|
|
if spec.can_refresh then
|
|
|
|
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
|
|
|
|
elseif frequency == Skill.Compulsory then
|
|
|
|
spec.priority = 2
|
|
|
|
else
|
|
|
|
spec.priority = 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if type(spec.priority) == "number" then
|
|
|
|
for _, event in ipairs(skill.events) do
|
|
|
|
skill.priority_table[event] = spec.priority
|
|
|
|
end
|
|
|
|
elseif type(spec.priority) == "table" then
|
|
|
|
for event, priority in pairs(spec.priority) do
|
|
|
|
skill.priority_table[event] = priority
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return skill
|
|
|
|
end
|
|
|
|
|
|
|
|
---@class ActiveSkillSpec: SkillSpec
|
|
|
|
---@field can_use fun(self: ActiveSkill, player: Player): boolean
|
|
|
|
---@field card_filter fun(self: ActiveSkill, to_select: integer, selected: integer[], selected_targets: integer[]): boolean
|
|
|
|
---@field target_filter fun(self: ActiveSkill, to_select: integer, selected: integer[], selected_cards: integer[]): boolean
|
2022-09-14 05:01:10 +00:00
|
|
|
---@field feasible fun(self: ActiveSkill, selected: integer[], selected_cards: integer[]): boolean
|
2022-04-30 07:27:56 +00:00
|
|
|
---@field on_use fun(self: ActiveSkill, room: Room, cardUseEvent: CardUseStruct): boolean
|
|
|
|
---@field on_effect fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent): boolean
|
2022-12-20 10:40:17 +00:00
|
|
|
---@field on_nullified fun(self: ActiveSkill, room: Room, cardEffectEvent: CardEffectEvent): boolean
|
2022-04-30 07:27:56 +00:00
|
|
|
|
|
|
|
---@param spec ActiveSkillSpec
|
|
|
|
---@return ActiveSkill
|
|
|
|
function fk.CreateActiveSkill(spec)
|
|
|
|
assert(type(spec.name) == "string")
|
|
|
|
local skill = ActiveSkill:new(spec.name)
|
|
|
|
if spec.can_use then skill.canUse = spec.can_use end
|
|
|
|
if spec.card_filter then skill.cardFilter = spec.card_filter end
|
|
|
|
if spec.target_filter then skill.targetFilter = spec.target_filter end
|
|
|
|
if spec.feasible then skill.feasible = spec.feasible end
|
|
|
|
if spec.on_use then skill.onUse = spec.on_use end
|
|
|
|
if spec.on_effect then skill.onEffect = spec.on_effect end
|
2022-12-20 10:40:17 +00:00
|
|
|
if spec.on_nullified then skill.onNullified = spec.on_nullified end
|
2022-04-30 07:27:56 +00:00
|
|
|
return skill
|
|
|
|
end
|
|
|
|
|
2023-01-04 06:21:29 +00:00
|
|
|
---@class DistanceSpec: SkillSpec
|
|
|
|
---@field correct_func fun(self: DistanceSkill, from: Player, to: Player)
|
|
|
|
---@field global boolean
|
|
|
|
|
|
|
|
---@param spec DistanceSpec
|
|
|
|
---@return DistanceSkill
|
|
|
|
function fk.CreateDistanceSkill(spec)
|
|
|
|
assert(type(spec.name) == "string")
|
|
|
|
assert(type(spec.correct_func) == "function")
|
|
|
|
|
|
|
|
local skill = DistanceSkill:new(spec.name)
|
|
|
|
skill.getCorrect = spec.correct_func
|
|
|
|
if spec.global then
|
|
|
|
skill.global = spec.global
|
|
|
|
end
|
|
|
|
|
|
|
|
return skill
|
|
|
|
end
|
|
|
|
|
2022-04-30 07:27:56 +00:00
|
|
|
---@class CardSpec: Card
|
|
|
|
---@field skill Skill
|
|
|
|
|
|
|
|
local defaultCardSkill = fk.CreateActiveSkill{
|
|
|
|
name = "default_card_skill",
|
|
|
|
on_use = function(self, room, use)
|
|
|
|
if not use.tos or #TargetGroup:getRealTargets(use.tos) == 0 then
|
|
|
|
use.tos = { { use.from } }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
2022-04-02 13:39:44 +00:00
|
|
|
---@param spec CardSpec
|
2022-03-31 05:29:23 +00:00
|
|
|
---@return BasicCard
|
|
|
|
function fk.CreateBasicCard(spec)
|
2022-04-30 07:27:56 +00:00
|
|
|
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
|
|
|
if not spec.name then spec.name = spec.class_name
|
|
|
|
elseif not spec.class_name then spec.class_name = spec.name end
|
|
|
|
if spec.suit then assert(type(spec.suit) == "number") end
|
|
|
|
if spec.number then assert(type(spec.number) == "number") end
|
|
|
|
|
|
|
|
local card = BasicCard:new(spec.name, spec.suit, spec.number)
|
|
|
|
card.skill = spec.skill or defaultCardSkill
|
|
|
|
return card
|
2022-03-31 05:29:23 +00:00
|
|
|
end
|
|
|
|
|
2022-04-02 13:39:44 +00:00
|
|
|
---@param spec CardSpec
|
2022-03-31 05:29:23 +00:00
|
|
|
---@return TrickCard
|
|
|
|
function fk.CreateTrickCard(spec)
|
2022-04-30 07:27:56 +00:00
|
|
|
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
|
|
|
if not spec.name then spec.name = spec.class_name
|
|
|
|
elseif not spec.class_name then spec.class_name = spec.name end
|
|
|
|
if spec.suit then assert(type(spec.suit) == "number") end
|
|
|
|
if spec.number then assert(type(spec.number) == "number") end
|
|
|
|
|
|
|
|
local card = TrickCard:new(spec.name, spec.suit, spec.number)
|
|
|
|
card.skill = spec.skill or defaultCardSkill
|
|
|
|
return card
|
2022-03-31 05:29:23 +00:00
|
|
|
end
|
|
|
|
|
2022-04-02 13:39:44 +00:00
|
|
|
---@param spec CardSpec
|
2022-04-08 10:39:58 +00:00
|
|
|
---@return DelayedTrickCard
|
|
|
|
function fk.CreateDelayedTrickCard(spec)
|
2022-04-30 07:27:56 +00:00
|
|
|
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
|
|
|
if not spec.name then spec.name = spec.class_name
|
|
|
|
elseif not spec.class_name then spec.class_name = spec.name end
|
|
|
|
if spec.suit then assert(type(spec.suit) == "number") end
|
|
|
|
if spec.number then assert(type(spec.number) == "number") end
|
|
|
|
|
|
|
|
local card = DelayedTrickCard:new(spec.name, spec.suit, spec.number)
|
|
|
|
card.skill = spec.skill or defaultCardSkill
|
|
|
|
return card
|
2022-04-08 10:39:58 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
---@param spec CardSpec
|
|
|
|
---@return Weapon
|
|
|
|
function fk.CreateWeapon(spec)
|
2022-04-30 07:27:56 +00:00
|
|
|
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
|
|
|
if not spec.name then spec.name = spec.class_name
|
|
|
|
elseif not spec.class_name then spec.class_name = spec.name end
|
|
|
|
if spec.suit then assert(type(spec.suit) == "number") end
|
|
|
|
if spec.number then assert(type(spec.number) == "number") end
|
|
|
|
if spec.attack_range then assert(type(spec.attack_range) == "number" and spec.attack_range >= 0) end
|
|
|
|
|
|
|
|
local card = Weapon:new(spec.name, spec.suit, spec.number, spec.attack_range)
|
|
|
|
card.skill = spec.skill or defaultCardSkill
|
|
|
|
return card
|
2022-04-08 10:39:58 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
---@param spec CardSpec
|
|
|
|
---@return Armor
|
|
|
|
function fk.CreateArmor(spec)
|
2022-04-30 07:27:56 +00:00
|
|
|
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
|
|
|
if not spec.name then spec.name = spec.class_name
|
|
|
|
elseif not spec.class_name then spec.class_name = spec.name end
|
|
|
|
if spec.suit then assert(type(spec.suit) == "number") end
|
|
|
|
if spec.number then assert(type(spec.number) == "number") end
|
|
|
|
|
|
|
|
local card = Armor:new(spec.name, spec.suit, spec.number)
|
|
|
|
card.skill = spec.skill or defaultCardSkill
|
|
|
|
return card
|
2022-04-08 10:39:58 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
---@param spec CardSpec
|
|
|
|
---@return DefensiveRide
|
|
|
|
function fk.CreateDefensiveRide(spec)
|
2022-04-30 07:27:56 +00:00
|
|
|
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
|
|
|
if not spec.name then spec.name = spec.class_name
|
|
|
|
elseif not spec.class_name then spec.class_name = spec.name end
|
|
|
|
if spec.suit then assert(type(spec.suit) == "number") end
|
|
|
|
if spec.number then assert(type(spec.number) == "number") end
|
|
|
|
|
|
|
|
local card = DefensiveRide:new(spec.name, spec.suit, spec.number)
|
|
|
|
card.skill = spec.skill or defaultCardSkill
|
|
|
|
return card
|
2022-04-08 10:39:58 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
---@param spec CardSpec
|
|
|
|
---@return OffensiveRide
|
|
|
|
function fk.CreateOffensiveRide(spec)
|
2022-04-30 07:27:56 +00:00
|
|
|
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
|
|
|
if not spec.name then spec.name = spec.class_name
|
|
|
|
elseif not spec.class_name then spec.class_name = spec.name end
|
|
|
|
if spec.suit then assert(type(spec.suit) == "number") end
|
|
|
|
if spec.number then assert(type(spec.number) == "number") end
|
|
|
|
|
|
|
|
local card = OffensiveRide:new(spec.name, spec.suit, spec.number)
|
|
|
|
card.skill = spec.skill or defaultCardSkill
|
|
|
|
return card
|
2022-04-08 10:39:58 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
---@param spec CardSpec
|
|
|
|
---@return Treasure
|
|
|
|
function fk.CreateTreasure(spec)
|
2022-04-30 07:27:56 +00:00
|
|
|
assert(type(spec.name) == "string" or type(spec.class_name) == "string")
|
|
|
|
if not spec.name then spec.name = spec.class_name
|
|
|
|
elseif not spec.class_name then spec.class_name = spec.name end
|
|
|
|
if spec.suit then assert(type(spec.suit) == "number") end
|
|
|
|
if spec.number then assert(type(spec.number) == "number") end
|
|
|
|
|
|
|
|
local card = Treasure:new(spec.name, spec.suit, spec.number)
|
|
|
|
card.skill = spec.skill or defaultCardSkill
|
|
|
|
return card
|
2022-04-01 12:51:01 +00:00
|
|
|
end
|