2023-04-09 05:35:35 +00:00
|
|
|
|
-- SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
2023-03-29 15:27:11 +00:00
|
|
|
|
--- Card记录了FreeKill所有卡牌的基础信息。
|
|
|
|
|
---
|
|
|
|
|
--- 它包含了ID、所属包、牌名、花色、点数等等
|
|
|
|
|
---
|
2022-03-31 05:29:23 +00:00
|
|
|
|
---@class Card : Object
|
2023-03-29 15:27:11 +00:00
|
|
|
|
---@field public id integer @ 标志某一张卡牌唯一的数字,从1开始。若此牌是虚拟牌,则其id为0。服务器启动时为卡牌赋予ID。
|
|
|
|
|
---@field public package Package @ 卡牌所属的扩展包
|
|
|
|
|
---@field public name string @ 卡牌的名字
|
|
|
|
|
---@field public suit Suit @ 卡牌的花色(四色及无花色)
|
|
|
|
|
---@field public number integer @ 卡牌的点数(0到K)
|
|
|
|
|
---@field public trueName string @ 卡牌的真名,一般用于分辨杀。
|
|
|
|
|
---@field public color Color @ 卡牌的颜色(分为黑色、红色、无色)
|
|
|
|
|
---@field public type CardType @ 卡牌的种类(基本牌、锦囊牌、装备牌)
|
|
|
|
|
---@field public sub_type CardSubtype @ 卡牌的子种类(例如延时锦囊牌、武器、防具等)
|
|
|
|
|
---@field public area CardArea @ 卡牌所在区域(例如手牌区,判定区,装备区,牌堆,弃牌堆···)
|
2023-04-21 14:49:49 +00:00
|
|
|
|
---@field public mark table<string, integer> @ 当前拥有的所有标记,用烂了
|
2023-06-03 15:59:04 +00:00
|
|
|
|
---@field public subcards integer[] @ 子卡ID表
|
|
|
|
|
---@field public skillName string @ 虚拟牌的技能名 for virtual cards
|
2023-06-23 14:18:11 +00:00
|
|
|
|
---@field private _skillName string
|
2023-06-03 15:59:04 +00:00
|
|
|
|
---@field public skillNames string[] @ 虚拟牌的技能名们(一张虚拟牌可能有多个技能名,如芳魂、龙胆、朱雀羽扇)
|
|
|
|
|
---@field public skill Skill @ 技能(用于实现卡牌效果)
|
|
|
|
|
---@field public special_skills string[] | nil @ 衍生技能,如重铸
|
|
|
|
|
---@field public is_damage_card boolean @ 是否为会造成伤害的牌
|
2023-07-11 15:16:46 +00:00
|
|
|
|
---@field public multiple_targets boolean @ 是否为指定多个目标的牌
|
2023-06-03 15:59:04 +00:00
|
|
|
|
---@field public is_derived boolean|null @ 判断是否为衍生牌
|
2022-03-31 05:29:23 +00:00
|
|
|
|
local Card = class("Card")
|
2022-01-24 02:23:08 +00:00
|
|
|
|
|
2022-04-01 12:51:01 +00:00
|
|
|
|
---@alias Suit integer
|
|
|
|
|
|
|
|
|
|
Card.Spade = 1
|
|
|
|
|
Card.Club = 2
|
|
|
|
|
Card.Heart = 3
|
|
|
|
|
Card.Diamond = 4
|
|
|
|
|
Card.NoSuit = 5
|
|
|
|
|
|
|
|
|
|
---@alias Color integer
|
|
|
|
|
|
|
|
|
|
Card.Black = 1
|
|
|
|
|
Card.Red = 2
|
|
|
|
|
Card.NoColor = 3
|
|
|
|
|
|
|
|
|
|
---@alias CardType integer
|
|
|
|
|
|
2022-04-30 07:27:56 +00:00
|
|
|
|
Card.TypeBasic = 1
|
|
|
|
|
Card.TypeTrick = 2
|
|
|
|
|
Card.TypeEquip = 3
|
2022-01-24 02:23:08 +00:00
|
|
|
|
|
2022-04-08 10:39:58 +00:00
|
|
|
|
---@alias CardSubtype integer
|
|
|
|
|
|
|
|
|
|
Card.SubtypeNone = 1
|
|
|
|
|
Card.SubtypeDelayedTrick = 2
|
|
|
|
|
Card.SubtypeWeapon = 3
|
|
|
|
|
Card.SubtypeArmor = 4
|
|
|
|
|
Card.SubtypeDefensiveRide = 5
|
|
|
|
|
Card.SubtypeOffensiveRide = 6
|
|
|
|
|
Card.SubtypeTreasure = 7
|
|
|
|
|
|
|
|
|
|
---@alias CardArea integer
|
|
|
|
|
|
|
|
|
|
Card.Unknown = 0
|
|
|
|
|
Card.PlayerHand = 1
|
|
|
|
|
Card.PlayerEquip = 2
|
|
|
|
|
Card.PlayerJudge = 3
|
|
|
|
|
Card.PlayerSpecial = 4
|
|
|
|
|
Card.Processing = 5
|
|
|
|
|
Card.DrawPile = 6
|
|
|
|
|
Card.DiscardPile = 7
|
|
|
|
|
Card.Void = 8
|
|
|
|
|
|
2023-03-29 15:27:11 +00:00
|
|
|
|
--- Card的构造函数。具体负责构建Card实例的函数,请参见fk_ex部分。
|
2022-03-31 05:29:23 +00:00
|
|
|
|
function Card:initialize(name, suit, number, color)
|
2022-04-30 07:27:56 +00:00
|
|
|
|
self.name = name
|
|
|
|
|
self.suit = suit or Card.NoSuit
|
|
|
|
|
self.number = number or 0
|
2023-02-21 05:44:24 +00:00
|
|
|
|
|
2023-06-04 11:40:14 +00:00
|
|
|
|
if string.sub(name, 1, 1) == "&" then
|
|
|
|
|
self.name = string.sub(name, 2, #name)
|
|
|
|
|
self.is_derived = true
|
|
|
|
|
end
|
|
|
|
|
|
2023-06-24 04:29:20 +00:00
|
|
|
|
local name_splited = self.name:split("__")
|
2023-02-21 05:44:24 +00:00
|
|
|
|
self.trueName = name_splited[#name_splited]
|
2022-01-24 02:23:08 +00:00
|
|
|
|
|
2022-04-30 07:27:56 +00:00
|
|
|
|
if suit == Card.Spade or suit == Card.Club then
|
|
|
|
|
self.color = Card.Black
|
|
|
|
|
elseif suit == Card.Heart or suit == Card.Diamond then
|
|
|
|
|
self.color = Card.Red
|
|
|
|
|
elseif color ~= nil then
|
|
|
|
|
self.color = color
|
|
|
|
|
else
|
|
|
|
|
self.color = Card.NoColor
|
|
|
|
|
end
|
2022-01-24 02:23:08 +00:00
|
|
|
|
|
2023-05-26 12:53:26 +00:00
|
|
|
|
-- self.package = nil
|
2022-04-30 07:27:56 +00:00
|
|
|
|
self.id = 0
|
|
|
|
|
self.type = 0
|
2023-06-23 14:18:11 +00:00
|
|
|
|
self.sub_type = Card.SubtypeNone
|
2023-05-26 12:53:26 +00:00
|
|
|
|
-- self.skill = nil
|
2023-01-16 11:13:07 +00:00
|
|
|
|
self.subcards = {}
|
2023-05-26 12:53:26 +00:00
|
|
|
|
-- self.skillName = nil
|
2023-04-02 04:56:29 +00:00
|
|
|
|
self._skillName = ""
|
|
|
|
|
self.skillNames = {}
|
2023-06-23 14:18:11 +00:00
|
|
|
|
-- self.mark = {} -- 这个视情况了,只有虚拟牌才有真正的self.mark,真牌的话挂在currentRoom
|
2023-05-26 12:53:26 +00:00
|
|
|
|
end
|
2023-05-20 08:00:03 +00:00
|
|
|
|
|
2023-05-26 12:53:26 +00:00
|
|
|
|
function Card:__index(k)
|
|
|
|
|
if k == "skillName" then
|
|
|
|
|
return self._skillName
|
2023-06-23 14:18:11 +00:00
|
|
|
|
elseif k == "mark" then
|
|
|
|
|
if not self:isVirtual() then
|
|
|
|
|
local mark_tab = Fk:currentRoom().card_marks
|
|
|
|
|
mark_tab[self.id] = mark_tab[self.id] or {}
|
|
|
|
|
return mark_tab[self.id]
|
|
|
|
|
else
|
|
|
|
|
self.mark = {}
|
|
|
|
|
return self.mark
|
|
|
|
|
end
|
2023-04-02 04:56:29 +00:00
|
|
|
|
end
|
2023-05-26 12:53:26 +00:00
|
|
|
|
end
|
2023-04-02 04:56:29 +00:00
|
|
|
|
|
2023-05-26 12:53:26 +00:00
|
|
|
|
function Card:__newindex(k, v)
|
|
|
|
|
if k == "skillName" then
|
|
|
|
|
table.insertIfNeed(self.skillNames, v)
|
|
|
|
|
self._skillName = v
|
|
|
|
|
else
|
|
|
|
|
rawset(self, k, v)
|
2023-04-02 04:56:29 +00:00
|
|
|
|
end
|
2023-01-16 11:13:07 +00:00
|
|
|
|
end
|
|
|
|
|
|
2023-04-09 03:44:19 +00:00
|
|
|
|
function Card:__tostring()
|
2023-04-20 20:29:52 +00:00
|
|
|
|
return string.format("<Card %s[%s %d]>", self.name, self:getSuitString(), self.number)
|
2023-04-09 03:44:19 +00:00
|
|
|
|
end
|
|
|
|
|
|
2023-03-29 15:27:11 +00:00
|
|
|
|
--- 克隆特定卡牌并赋予花色与点数。
|
|
|
|
|
---
|
|
|
|
|
--- 会将skill/special_skills/equip_skill继承到克隆牌中。
|
|
|
|
|
---@param suit Suit @ 克隆后的牌的花色
|
|
|
|
|
---@param number integer @ 克隆后的牌的点数
|
|
|
|
|
---@return Card @ 产品
|
2023-01-16 11:13:07 +00:00
|
|
|
|
function Card:clone(suit, number)
|
|
|
|
|
local newCard = self.class:new(self.name, suit, number)
|
|
|
|
|
newCard.skill = self.skill
|
2023-03-20 12:15:24 +00:00
|
|
|
|
newCard.special_skills = self.special_skills
|
2023-02-15 13:20:40 +00:00
|
|
|
|
newCard.equip_skill = self.equip_skill
|
2023-05-13 06:16:09 +00:00
|
|
|
|
newCard.attack_range = self.attack_range
|
2023-04-21 12:57:03 +00:00
|
|
|
|
newCard.is_damage_card = self.is_damage_card
|
2023-07-11 15:16:46 +00:00
|
|
|
|
newCard.multiple_targets = self.multiple_targets
|
2023-05-20 08:00:03 +00:00
|
|
|
|
newCard.is_derived = self.is_derived
|
2023-01-16 11:13:07 +00:00
|
|
|
|
return newCard
|
|
|
|
|
end
|
|
|
|
|
|
2023-03-29 15:27:11 +00:00
|
|
|
|
--- 检测是否为虚拟卡牌,如果其ID为0及以下,则为虚拟卡牌。
|
2023-01-16 11:13:07 +00:00
|
|
|
|
function Card:isVirtual()
|
|
|
|
|
return self.id <= 0
|
|
|
|
|
end
|
|
|
|
|
|
2023-03-29 15:27:11 +00:00
|
|
|
|
--- 获取卡牌的ID。
|
|
|
|
|
---
|
|
|
|
|
--- 如果牌是虚拟牌,则返回其第一张子卡的id,没有子卡就返回nil
|
|
|
|
|
---@return integer | nil
|
2023-01-16 11:13:07 +00:00
|
|
|
|
function Card:getEffectiveId()
|
|
|
|
|
if self:isVirtual() then
|
|
|
|
|
return #self.subcards > 0 and self.subcards[1] or nil
|
|
|
|
|
end
|
|
|
|
|
return self.id
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function updateColorAndNumber(card)
|
|
|
|
|
local color = Card.NoColor
|
|
|
|
|
local number = 0
|
|
|
|
|
local different_color = false
|
2023-04-19 16:19:48 +00:00
|
|
|
|
for i, id in ipairs(card.subcards) do
|
2023-01-16 11:13:07 +00:00
|
|
|
|
local c = Fk:getCardById(id)
|
|
|
|
|
number = math.min(number + c.number, 13)
|
2023-04-19 16:19:48 +00:00
|
|
|
|
if i == 1 then
|
|
|
|
|
card.suit = c.suit
|
|
|
|
|
else
|
|
|
|
|
card.suit = Card.NoSuit
|
|
|
|
|
end
|
|
|
|
|
|
2023-01-16 11:13:07 +00:00
|
|
|
|
if color ~= c.color then
|
|
|
|
|
if not different_color then
|
2023-04-13 12:17:39 +00:00
|
|
|
|
if c.color ~= Card.NoColor then
|
2023-01-16 11:13:07 +00:00
|
|
|
|
different_color = true
|
|
|
|
|
end
|
|
|
|
|
color = c.color
|
|
|
|
|
else
|
|
|
|
|
color = Card.NoColor
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
card.color = color
|
|
|
|
|
card.number = number
|
|
|
|
|
end
|
|
|
|
|
|
2023-03-29 15:27:11 +00:00
|
|
|
|
--- 将一张子卡牌加入某张牌中(是addSubcards的基础函数,常用addSubcards)。
|
|
|
|
|
---@param card integer|Card @ 要加入的子卡
|
2023-01-16 11:13:07 +00:00
|
|
|
|
function Card:addSubcard(card)
|
|
|
|
|
if type(card) == "number" then
|
|
|
|
|
table.insert(self.subcards, card)
|
|
|
|
|
else
|
|
|
|
|
assert(card:isInstanceOf(Card))
|
2023-04-13 12:17:39 +00:00
|
|
|
|
-- assert(not card:isVirtual(), "Can not add virtual card as subcard")
|
|
|
|
|
if card:isVirtual() then
|
|
|
|
|
table.insertTable(self.subcards, card.subcards)
|
|
|
|
|
else
|
|
|
|
|
table.insert(self.subcards, card.id)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
for _, skill in ipairs(card.skillNames) do
|
|
|
|
|
self.skillName = skill
|
|
|
|
|
end
|
2023-01-16 11:13:07 +00:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
updateColorAndNumber(self)
|
|
|
|
|
end
|
|
|
|
|
|
2023-03-29 15:27:11 +00:00
|
|
|
|
--- 将一批子卡牌加入某张牌中(常用于将这批牌弃置/交给某个角色···)。
|
|
|
|
|
---@param cards integer[] | Card[] @ 要加入的子卡列表
|
2023-01-16 11:13:07 +00:00
|
|
|
|
function Card:addSubcards(cards)
|
|
|
|
|
for _, c in ipairs(cards) do
|
|
|
|
|
self:addSubcard(c)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2023-03-29 15:27:11 +00:00
|
|
|
|
--- 清空加入某张牌中的子卡牌。
|
2023-01-16 11:13:07 +00:00
|
|
|
|
function Card:clearSubcards()
|
|
|
|
|
self.subcards = {}
|
|
|
|
|
updateColorAndNumber(self)
|
2022-03-25 04:28:07 +00:00
|
|
|
|
end
|
2022-01-24 02:23:08 +00:00
|
|
|
|
|
2023-03-29 15:27:11 +00:00
|
|
|
|
--- 判断此牌能否符合一个卡牌规则。
|
2023-01-29 10:11:41 +00:00
|
|
|
|
function Card:matchPattern(pattern)
|
|
|
|
|
return Exppattern:Parse(pattern):match(self)
|
|
|
|
|
end
|
|
|
|
|
|
2023-06-14 05:40:50 +00:00
|
|
|
|
--- 获取卡牌花色并返回花色文字描述(如 黑桃、红桃、梅花、方块)或者符号(如♠♥♣♦,带颜色)。
|
2023-07-14 14:17:54 +00:00
|
|
|
|
---@param symbol boolean|nil @ 是否以符号形式显示
|
2023-03-29 15:27:11 +00:00
|
|
|
|
---@return string @ 描述花色的字符串
|
2023-06-14 05:40:50 +00:00
|
|
|
|
function Card:getSuitString(symbol)
|
2022-04-30 07:27:56 +00:00
|
|
|
|
local suit = self.suit
|
2023-06-14 05:40:50 +00:00
|
|
|
|
local ret
|
2022-04-30 07:27:56 +00:00
|
|
|
|
if suit == Card.Spade then
|
2023-06-14 05:40:50 +00:00
|
|
|
|
ret = "spade"
|
2022-04-30 07:27:56 +00:00
|
|
|
|
elseif suit == Card.Heart then
|
2023-06-14 05:40:50 +00:00
|
|
|
|
ret = "heart"
|
2022-04-30 07:27:56 +00:00
|
|
|
|
elseif suit == Card.Club then
|
2023-06-14 05:40:50 +00:00
|
|
|
|
ret = "club"
|
2022-04-30 07:27:56 +00:00
|
|
|
|
elseif suit == Card.Diamond then
|
2023-06-14 05:40:50 +00:00
|
|
|
|
ret = "diamond"
|
2022-04-30 07:27:56 +00:00
|
|
|
|
else
|
2023-06-14 05:40:50 +00:00
|
|
|
|
ret = "nosuit"
|
2022-04-30 07:27:56 +00:00
|
|
|
|
end
|
2023-06-14 05:40:50 +00:00
|
|
|
|
return symbol and "log_" .. ret or ret
|
2022-04-14 10:22:00 +00:00
|
|
|
|
end
|
|
|
|
|
|
2023-03-29 15:27:11 +00:00
|
|
|
|
--- 获取卡牌颜色并返回点数颜色描述(例如黑色/红色/无色)。
|
|
|
|
|
---@return string @ 描述颜色的字符串
|
2023-01-16 11:13:07 +00:00
|
|
|
|
function Card:getColorString()
|
|
|
|
|
local color = self.color
|
|
|
|
|
if color == Card.Black then
|
|
|
|
|
return "black"
|
|
|
|
|
elseif color == Card.Red then
|
|
|
|
|
return "red"
|
|
|
|
|
end
|
|
|
|
|
return "nocolor"
|
|
|
|
|
end
|
|
|
|
|
|
2023-06-14 05:40:50 +00:00
|
|
|
|
--- 获取卡牌类型并返回类型描述(例如基本牌/锦囊牌/装备牌)。
|
2023-02-15 11:54:35 +00:00
|
|
|
|
function Card:getTypeString()
|
|
|
|
|
local t = self.type
|
|
|
|
|
if t == Card.TypeBasic then
|
|
|
|
|
return "basic"
|
|
|
|
|
elseif t == Card.TypeTrick then
|
|
|
|
|
return "trick"
|
|
|
|
|
elseif t == Card.TypeEquip then
|
|
|
|
|
return "equip"
|
|
|
|
|
end
|
2023-03-20 12:49:23 +00:00
|
|
|
|
return "notype"
|
2023-02-15 11:54:35 +00:00
|
|
|
|
end
|
|
|
|
|
|
2023-06-24 04:29:20 +00:00
|
|
|
|
local subtype_string_table = {
|
|
|
|
|
[Card.SubtypeArmor] = "armor",
|
|
|
|
|
[Card.SubtypeWeapon] = "weapon",
|
|
|
|
|
[Card.SubtypeTreasure] = "treasure",
|
|
|
|
|
[Card.SubtypeDelayedTrick] = "delayed_trick",
|
|
|
|
|
[Card.SubtypeDefensiveRide] = "defensive_ride",
|
|
|
|
|
[Card.SubtypeOffensiveRide] = "offensive_ride",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Card:getSubtypeString()
|
|
|
|
|
local t = self.sub_type
|
|
|
|
|
local ret = subtype_string_table[t]
|
|
|
|
|
if ret == nil then
|
|
|
|
|
if self.type == Card.TypeTrick then
|
|
|
|
|
return "normal_trick"
|
|
|
|
|
elseif self.type == Card.TypeBasic then
|
|
|
|
|
return "basic"
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
return ret
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2023-06-29 16:48:37 +00:00
|
|
|
|
--- 获取卡牌点数并返回点数文字描述(仅限A/J/Q/K/X)。
|
2022-12-18 04:52:52 +00:00
|
|
|
|
local function getNumberStr(num)
|
|
|
|
|
if num == 1 then
|
|
|
|
|
return "A"
|
|
|
|
|
elseif num == 11 then
|
|
|
|
|
return "J"
|
|
|
|
|
elseif num == 12 then
|
|
|
|
|
return "Q"
|
|
|
|
|
elseif num == 13 then
|
|
|
|
|
return "K"
|
2023-06-29 16:48:37 +00:00
|
|
|
|
elseif num == 0 then
|
|
|
|
|
return "X"
|
2022-12-18 04:52:52 +00:00
|
|
|
|
end
|
|
|
|
|
return tostring(num)
|
|
|
|
|
end
|
|
|
|
|
|
2023-06-29 16:48:37 +00:00
|
|
|
|
--- 获取卡牌点数并返回点数文字描述(仅限A/J/Q/K/X)。
|
|
|
|
|
---@param num integer @ 当你只想翻译点数为文字时(优先检查,请注意)
|
|
|
|
|
function Card:getNumberStr(num)
|
|
|
|
|
return tostring(getNumberStr(num and num or self.number))
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
--- 根据点数文字描述返回数字。
|
|
|
|
|
---@param str integer @ 只能翻译文字为点数
|
|
|
|
|
function Card:strToNumber(str)
|
|
|
|
|
if str == "A" then
|
|
|
|
|
return 1
|
|
|
|
|
elseif str == "J" then
|
|
|
|
|
return 11
|
|
|
|
|
elseif str == "Q" then
|
|
|
|
|
return 12
|
|
|
|
|
elseif str == "K" then
|
|
|
|
|
return 13
|
|
|
|
|
elseif str == "X" then
|
|
|
|
|
return 0
|
|
|
|
|
end
|
|
|
|
|
return tonumber(str)
|
|
|
|
|
end
|
|
|
|
|
|
2023-06-14 05:40:50 +00:00
|
|
|
|
--- 获取卡牌的完整点数(花色+点数),如(黑桃A/♠A)。
|
|
|
|
|
---@param symbol boolean @ 是否以符号形式显示花色
|
|
|
|
|
---@return string @ 完整点数(字符串)
|
|
|
|
|
function Card:getSuitCompletedString(symbol)
|
|
|
|
|
return self:getSuitString(symbol) .. getNumberStr(self.number)
|
|
|
|
|
end
|
|
|
|
|
|
2023-05-13 06:20:34 +00:00
|
|
|
|
--- 判断卡牌是否为普通锦囊牌
|
|
|
|
|
---@return boolean
|
|
|
|
|
function Card:isCommonTrick()
|
|
|
|
|
return self.type == Card.TypeTrick and self.sub_type ~= Card.SubtypeDelayedTrick
|
|
|
|
|
end
|
|
|
|
|
|
2023-04-21 14:49:49 +00:00
|
|
|
|
--- 为卡牌赋予Mark。
|
|
|
|
|
---@param mark string @ 标记
|
|
|
|
|
---@param count integer @ 为标记赋予的数量
|
|
|
|
|
-- mark name and UI:
|
|
|
|
|
-- 'xxx': invisible mark
|
|
|
|
|
-- '@mark': mark with extra data (maybe string or number)
|
|
|
|
|
-- '@@mark': mark without data
|
|
|
|
|
function Card: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
|
|
|
|
|
|
|
|
|
|
--- 为卡牌移除Mark。
|
|
|
|
|
---@param mark string @ 标记
|
|
|
|
|
---@param count integer @ 为标记删除的数量
|
|
|
|
|
function Card: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
|
|
|
|
|
|
|
|
|
|
--- 为卡牌设置Mark至指定数量。
|
2023-06-23 14:18:11 +00:00
|
|
|
|
---
|
|
|
|
|
--- 关于标记的说明:
|
|
|
|
|
---
|
|
|
|
|
--- * @开头的为可见标记,其余为隐藏标记。
|
|
|
|
|
--- * -turn结尾、-phase结尾、-round结尾的如同玩家标记一样在这个时机自动清理。
|
|
|
|
|
--- * -noclear结尾的表示不要自动清理。
|
|
|
|
|
--- * 默认的自动清理策略是当卡牌离开手牌区后清除所有的标记。
|
|
|
|
|
--- * -turn之类的后缀会覆盖默认清理的方式。
|
|
|
|
|
--- * (TODO: 以上皆为画饼)
|
2023-04-21 14:49:49 +00:00
|
|
|
|
---@param mark string @ 标记
|
|
|
|
|
---@param count integer @ 为标记删除的数量
|
|
|
|
|
function Card:setMark(mark, count)
|
2023-06-11 08:22:11 +00:00
|
|
|
|
if count == 0 then count = nil end
|
2023-04-21 14:49:49 +00:00
|
|
|
|
if self.mark[mark] ~= count then
|
|
|
|
|
self.mark[mark] = count
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
--- 获取卡牌对应Mark的数量。
|
|
|
|
|
---@param mark string @ 标记
|
2023-06-09 09:23:24 +00:00
|
|
|
|
---@return integer
|
2023-04-21 14:49:49 +00:00
|
|
|
|
function Card:getMark(mark)
|
2023-06-23 14:18:11 +00:00
|
|
|
|
local ret = (self.mark[mark] or 0)
|
|
|
|
|
if (not self:isVirtual()) and next(self.mark) == nil then
|
|
|
|
|
self.mark = nil
|
|
|
|
|
end
|
|
|
|
|
return ret
|
2023-04-21 14:49:49 +00:00
|
|
|
|
end
|
|
|
|
|
|
2023-06-09 09:23:24 +00:00
|
|
|
|
--- 判定卡牌是否拥有对应的Mark。
|
|
|
|
|
---@param mark string @ 标记
|
|
|
|
|
---@return boolean
|
|
|
|
|
function Card:hasMark(mark)
|
2023-06-11 08:53:27 +00:00
|
|
|
|
fk.qWarning("hasMark will be deleted in future version!")
|
2023-06-09 09:23:24 +00:00
|
|
|
|
return self:getMark(mark) ~= 0
|
|
|
|
|
end
|
|
|
|
|
|
2023-04-21 14:49:49 +00:00
|
|
|
|
--- 获取卡牌有哪些Mark。
|
|
|
|
|
function Card:getMarkNames()
|
|
|
|
|
local ret = {}
|
|
|
|
|
for k, _ in pairs(self.mark) do
|
|
|
|
|
table.insert(ret, k)
|
|
|
|
|
end
|
|
|
|
|
return ret
|
|
|
|
|
end
|
|
|
|
|
|
2023-06-03 15:59:04 +00:00
|
|
|
|
--- 比较两张卡牌的花色是否相同
|
|
|
|
|
---@param anotherCard Card @ 另一张卡牌
|
|
|
|
|
---@param diff boolean @ 比较二者相同还是不同
|
|
|
|
|
---@return boolean 返回比较结果
|
2023-05-13 06:20:34 +00:00
|
|
|
|
function Card:compareSuitWith(anotherCard, diff)
|
2023-05-13 07:03:35 +00:00
|
|
|
|
if self ~= anotherCard and table.contains({ self.suit, anotherCard.suit }, Card.NoSuit) then
|
2023-05-13 06:20:34 +00:00
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if diff then
|
|
|
|
|
return self.suit ~= anotherCard.suit
|
|
|
|
|
else
|
|
|
|
|
return self.suit == anotherCard.suit
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2023-06-03 15:59:04 +00:00
|
|
|
|
--- 比较两张卡牌的颜色是否相同
|
|
|
|
|
---@param anotherCard Card @ 另一张卡牌
|
|
|
|
|
---@param diff boolean @ 比较二者相同还是不同
|
|
|
|
|
---@return boolean 返回比较结果
|
2023-05-13 06:20:34 +00:00
|
|
|
|
function Card:compareColorWith(anotherCard, diff)
|
2023-05-13 07:03:35 +00:00
|
|
|
|
if self ~= anotherCard and table.contains({ self.color, anotherCard.color }, Card.NoColor) then
|
2023-05-13 06:20:34 +00:00
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if diff then
|
|
|
|
|
return self.color ~= anotherCard.color
|
|
|
|
|
else
|
|
|
|
|
return self.color == anotherCard.color
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2023-06-03 15:59:04 +00:00
|
|
|
|
--- 比较两张卡牌的点数是否相同
|
|
|
|
|
---@param anotherCard Card @ 另一张卡牌
|
|
|
|
|
---@param diff boolean @ 比较二者相同还是不同
|
|
|
|
|
---@return boolean 返回比较结果
|
2023-05-13 06:20:34 +00:00
|
|
|
|
function Card:compareNumberWith(anotherCard, diff)
|
2023-05-13 07:03:35 +00:00
|
|
|
|
if self ~= anotherCard and self.number < 1 or anotherCard.number < 1 then
|
2023-05-13 06:20:34 +00:00
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if diff then
|
|
|
|
|
return self.number ~= anotherCard.number
|
|
|
|
|
else
|
|
|
|
|
return self.number == anotherCard.number
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2022-12-18 04:52:52 +00:00
|
|
|
|
-- for sendLog
|
2023-03-29 15:27:11 +00:00
|
|
|
|
--- 获取卡牌的文字信息并准备作为log发送。
|
2022-12-18 04:52:52 +00:00
|
|
|
|
function Card:toLogString()
|
|
|
|
|
local ret = string.format('<font color="#0598BC"><b>%s</b></font>', Fk:translate(self.name) .. "[")
|
2023-04-19 16:19:48 +00:00
|
|
|
|
if self:isVirtual() and #self.subcards ~= 1 then
|
2023-01-16 11:13:07 +00:00
|
|
|
|
ret = ret .. Fk:translate(self:getColorString())
|
|
|
|
|
else
|
|
|
|
|
ret = ret .. Fk:translate("log_" .. self:getSuitString())
|
|
|
|
|
if self.number > 0 then
|
|
|
|
|
ret = ret .. string.format('<font color="%s"><b>%s</b></font>', self.color == Card.Red and "#CC3131" or "black", getNumberStr(self.number))
|
|
|
|
|
end
|
2022-12-18 04:52:52 +00:00
|
|
|
|
end
|
|
|
|
|
ret = ret .. '<font color="#0598BC"><b>]</b></font>'
|
|
|
|
|
return ret
|
|
|
|
|
end
|
|
|
|
|
|
2023-03-29 15:27:11 +00:00
|
|
|
|
--- 静态方法。传入下列类型之一的参数,返回id列表。
|
2023-02-21 05:44:24 +00:00
|
|
|
|
---@param c integer|integer[]|Card|Card[]
|
|
|
|
|
---@return integer[]
|
2023-03-26 09:32:45 +00:00
|
|
|
|
function Card:getIdList(c)
|
|
|
|
|
error("This is a static method. Please use Card:getIdList instead")
|
|
|
|
|
end
|
|
|
|
|
|
2023-02-21 05:44:24 +00:00
|
|
|
|
function Card.static:getIdList(c)
|
|
|
|
|
if type(c) == "number" then
|
|
|
|
|
return {c}
|
|
|
|
|
end
|
|
|
|
|
if c.class and c:isInstanceOf(Card) then
|
|
|
|
|
if c:isVirtual() then
|
|
|
|
|
return table.clone(c.subcards)
|
|
|
|
|
else
|
|
|
|
|
return {c.id}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- array
|
|
|
|
|
local ret = {}
|
|
|
|
|
for _, c2 in ipairs(c) do
|
2023-03-01 13:41:16 +00:00
|
|
|
|
table.insertTable(ret, Card:getIdList(c2))
|
2023-02-21 05:44:24 +00:00
|
|
|
|
end
|
|
|
|
|
return ret
|
|
|
|
|
end
|
|
|
|
|
|
2022-01-24 02:23:08 +00:00
|
|
|
|
return Card
|