530 lines
18 KiB
Python
530 lines
18 KiB
Python
|
|
"""三国杀游戏核心逻辑模块"""
|
|||
|
|
import logging
|
|||
|
|
from typing import List, Dict, Optional, Set
|
|||
|
|
from enum import Enum
|
|||
|
|
from dataclasses import dataclass, field
|
|||
|
|
import random
|
|||
|
|
|
|||
|
|
logger = logging.getLogger(__name__)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class CardType(Enum):
|
|||
|
|
"""卡牌类型"""
|
|||
|
|
BASIC = "基本牌"
|
|||
|
|
TRICK = "锦囊牌"
|
|||
|
|
EQUIPMENT = "装备牌"
|
|||
|
|
|
|||
|
|
|
|||
|
|
class CardSuit(Enum):
|
|||
|
|
"""卡牌花色"""
|
|||
|
|
SPADE = "♠" # 黑桃
|
|||
|
|
HEART = "♥" # 红桃
|
|||
|
|
CLUB = "♣" # 梅花
|
|||
|
|
DIAMOND = "♦" # 方块
|
|||
|
|
|
|||
|
|
|
|||
|
|
class CardColor(Enum):
|
|||
|
|
"""卡牌颜色"""
|
|||
|
|
RED = "红色"
|
|||
|
|
BLACK = "黑色"
|
|||
|
|
|
|||
|
|
|
|||
|
|
class Role(Enum):
|
|||
|
|
"""角色身份"""
|
|||
|
|
LORD = "主公"
|
|||
|
|
LOYAL = "忠臣"
|
|||
|
|
REBEL = "反贼"
|
|||
|
|
SPY = "内奸"
|
|||
|
|
|
|||
|
|
|
|||
|
|
class Phase(Enum):
|
|||
|
|
"""回合阶段"""
|
|||
|
|
PREPARE = "准备阶段"
|
|||
|
|
JUDGE = "判定阶段"
|
|||
|
|
DRAW = "摸牌阶段"
|
|||
|
|
PLAY = "出牌阶段"
|
|||
|
|
DISCARD = "弃牌阶段"
|
|||
|
|
END = "结束阶段"
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dataclass
|
|||
|
|
class Card:
|
|||
|
|
"""卡牌"""
|
|||
|
|
name: str # 卡牌名称
|
|||
|
|
card_type: CardType # 卡牌类型
|
|||
|
|
suit: CardSuit # 花色
|
|||
|
|
number: int # 点数 (1-13)
|
|||
|
|
description: str = "" # 描述
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def color(self) -> CardColor:
|
|||
|
|
"""获取卡牌颜色"""
|
|||
|
|
if self.suit in [CardSuit.HEART, CardSuit.DIAMOND]:
|
|||
|
|
return CardColor.RED
|
|||
|
|
return CardColor.BLACK
|
|||
|
|
|
|||
|
|
def __str__(self) -> str:
|
|||
|
|
"""字符串表示"""
|
|||
|
|
return f"{self.suit.value}{self.number} {self.name}"
|
|||
|
|
|
|||
|
|
def to_dict(self) -> Dict:
|
|||
|
|
"""转换为字典"""
|
|||
|
|
return {
|
|||
|
|
"name": self.name,
|
|||
|
|
"type": self.card_type.value,
|
|||
|
|
"suit": self.suit.value,
|
|||
|
|
"number": self.number,
|
|||
|
|
"color": self.color.value,
|
|||
|
|
"description": self.description
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dataclass
|
|||
|
|
class Skill:
|
|||
|
|
"""技能"""
|
|||
|
|
name: str # 技能名称
|
|||
|
|
description: str # 技能描述
|
|||
|
|
skill_type: str = "主动" # 技能类型: 主动/锁定/限定/觉醒
|
|||
|
|
|
|||
|
|
def to_dict(self) -> Dict:
|
|||
|
|
"""转换为字典"""
|
|||
|
|
return {
|
|||
|
|
"name": self.name,
|
|||
|
|
"description": self.description,
|
|||
|
|
"type": self.skill_type
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dataclass
|
|||
|
|
class General:
|
|||
|
|
"""武将"""
|
|||
|
|
name: str # 武将名称
|
|||
|
|
max_hp: int # 体力上限
|
|||
|
|
skills: List[Skill] # 技能列表
|
|||
|
|
kingdom: str = "魏" # 势力
|
|||
|
|
|
|||
|
|
def to_dict(self) -> Dict:
|
|||
|
|
"""转换为字典"""
|
|||
|
|
return {
|
|||
|
|
"name": self.name,
|
|||
|
|
"max_hp": self.max_hp,
|
|||
|
|
"kingdom": self.kingdom,
|
|||
|
|
"skills": [skill.to_dict() for skill in self.skills]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dataclass
|
|||
|
|
class Player:
|
|||
|
|
"""玩家"""
|
|||
|
|
user_id: int # 用户ID
|
|||
|
|
username: str # 用户名
|
|||
|
|
general: Optional[General] = None # 武将
|
|||
|
|
role: Optional[Role] = None # 身份
|
|||
|
|
hp: int = 0 # 当前体力
|
|||
|
|
hand_cards: List[Card] = field(default_factory=list) # 手牌
|
|||
|
|
equipment: Dict[str, Card] = field(default_factory=dict) # 装备区
|
|||
|
|
judge_area: List[Card] = field(default_factory=list) # 判定区
|
|||
|
|
is_alive: bool = True # 是否存活
|
|||
|
|
is_chained: bool = False # 是否横置
|
|||
|
|
|
|||
|
|
def __post_init__(self):
|
|||
|
|
"""初始化后处理"""
|
|||
|
|
if self.general and self.hp == 0:
|
|||
|
|
self.hp = self.general.max_hp
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def hand_count(self) -> int:
|
|||
|
|
"""手牌数量"""
|
|||
|
|
return len(self.hand_cards)
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def attack_range(self) -> int:
|
|||
|
|
"""攻击距离"""
|
|||
|
|
weapon = self.equipment.get("武器")
|
|||
|
|
if weapon:
|
|||
|
|
# 根据武器名称返回距离
|
|||
|
|
weapon_ranges = {
|
|||
|
|
"诸葛连弩": 1,
|
|||
|
|
"青釭剑": 2,
|
|||
|
|
"雌雄双股剑": 2,
|
|||
|
|
"青龙偃月刀": 3,
|
|||
|
|
"丈八蛇矛": 3,
|
|||
|
|
"方天画戟": 4,
|
|||
|
|
"麒麟弓": 5
|
|||
|
|
}
|
|||
|
|
return weapon_ranges.get(weapon.name, 1)
|
|||
|
|
return 1
|
|||
|
|
|
|||
|
|
def add_card(self, card: Card):
|
|||
|
|
"""添加手牌"""
|
|||
|
|
self.hand_cards.append(card)
|
|||
|
|
|
|||
|
|
def remove_card(self, card: Card) -> bool:
|
|||
|
|
"""移除手牌"""
|
|||
|
|
if card in self.hand_cards:
|
|||
|
|
self.hand_cards.remove(card)
|
|||
|
|
return True
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def take_damage(self, damage: int) -> bool:
|
|||
|
|
"""受到伤害
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
是否死亡
|
|||
|
|
"""
|
|||
|
|
self.hp -= damage
|
|||
|
|
if self.hp <= 0:
|
|||
|
|
self.is_alive = False
|
|||
|
|
return True
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def recover(self, amount: int):
|
|||
|
|
"""回复体力"""
|
|||
|
|
if self.general:
|
|||
|
|
self.hp = min(self.hp + amount, self.general.max_hp)
|
|||
|
|
|
|||
|
|
def to_dict(self) -> Dict:
|
|||
|
|
"""转换为字典"""
|
|||
|
|
return {
|
|||
|
|
"user_id": self.user_id,
|
|||
|
|
"username": self.username,
|
|||
|
|
"general": self.general.to_dict() if self.general else None,
|
|||
|
|
"role": self.role.value if self.role else None,
|
|||
|
|
"hp": self.hp,
|
|||
|
|
"max_hp": self.general.max_hp if self.general else 0,
|
|||
|
|
"hand_count": self.hand_count,
|
|||
|
|
"equipment": {k: v.to_dict() for k, v in self.equipment.items()},
|
|||
|
|
"is_alive": self.is_alive,
|
|||
|
|
"is_chained": self.is_chained
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
class CardDeck:
|
|||
|
|
"""牌堆"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
"""初始化牌堆"""
|
|||
|
|
self.cards: List[Card] = []
|
|||
|
|
self.discard_pile: List[Card] = []
|
|||
|
|
self._init_standard_deck()
|
|||
|
|
|
|||
|
|
def _init_standard_deck(self):
|
|||
|
|
"""初始化标准牌堆(简化版)"""
|
|||
|
|
# 杀 (30张)
|
|||
|
|
for suit, numbers in [
|
|||
|
|
(CardSuit.SPADE, [7, 8, 8, 9, 9, 10, 10]),
|
|||
|
|
(CardSuit.CLUB, [2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11]),
|
|||
|
|
(CardSuit.HEART, [10, 10, 11]),
|
|||
|
|
(CardSuit.DIAMOND, [6, 7, 8, 9, 10, 13])
|
|||
|
|
]:
|
|||
|
|
for num in numbers:
|
|||
|
|
self.cards.append(Card("杀", CardType.BASIC, suit, num, "对攻击范围内的一名角色造成1点伤害"))
|
|||
|
|
|
|||
|
|
# 闪 (15张)
|
|||
|
|
for suit, numbers in [
|
|||
|
|
(CardSuit.HEART, [2, 2, 13]),
|
|||
|
|
(CardSuit.DIAMOND, [2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11])
|
|||
|
|
]:
|
|||
|
|
for num in numbers:
|
|||
|
|
self.cards.append(Card("闪", CardType.BASIC, suit, num, "抵消一张【杀】的效果"))
|
|||
|
|
|
|||
|
|
# 桃 (8张)
|
|||
|
|
for suit, numbers in [
|
|||
|
|
(CardSuit.HEART, [3, 4, 6, 7, 8, 9, 12]),
|
|||
|
|
(CardSuit.DIAMOND, [12])
|
|||
|
|
]:
|
|||
|
|
for num in numbers:
|
|||
|
|
self.cards.append(Card("桃", CardType.BASIC, suit, num, "回复1点体力"))
|
|||
|
|
|
|||
|
|
# 锦囊牌
|
|||
|
|
# 无懈可击 (3张)
|
|||
|
|
for suit, num in [(CardSuit.SPADE, 11), (CardSuit.CLUB, 12), (CardSuit.CLUB, 13)]:
|
|||
|
|
self.cards.append(Card("无懈可击", CardType.TRICK, suit, num, "抵消一张锦囊牌的效果"))
|
|||
|
|
|
|||
|
|
# 决斗 (3张)
|
|||
|
|
for suit, num in [(CardSuit.SPADE, 1), (CardSuit.CLUB, 1), (CardSuit.DIAMOND, 1)]:
|
|||
|
|
self.cards.append(Card("决斗", CardType.TRICK, suit, num, "与目标角色拼点,失败者受到1点伤害"))
|
|||
|
|
|
|||
|
|
# 过河拆桥 (6张)
|
|||
|
|
for suit, numbers in [
|
|||
|
|
(CardSuit.SPADE, [3, 4, 12]),
|
|||
|
|
(CardSuit.CLUB, [3, 4]),
|
|||
|
|
(CardSuit.HEART, [12])
|
|||
|
|
]:
|
|||
|
|
for num in numbers:
|
|||
|
|
self.cards.append(Card("过河拆桥", CardType.TRICK, suit, num, "弃置目标角色的一张牌"))
|
|||
|
|
|
|||
|
|
# 顺手牵羊 (5张)
|
|||
|
|
for suit, numbers in [
|
|||
|
|
(CardSuit.SPADE, [3, 4, 11]),
|
|||
|
|
(CardSuit.DIAMOND, [3, 4])
|
|||
|
|
]:
|
|||
|
|
for num in numbers:
|
|||
|
|
self.cards.append(Card("顺手牵羊", CardType.TRICK, suit, num, "获得目标角色的一张牌"))
|
|||
|
|
|
|||
|
|
# 南蛮入侵 (3张)
|
|||
|
|
for suit, num in [(CardSuit.SPADE, 7), (CardSuit.SPADE, 13), (CardSuit.CLUB, 7)]:
|
|||
|
|
self.cards.append(Card("南蛮入侵", CardType.TRICK, suit, num, "所有其他角色需打出【杀】,否则受到1点伤害"))
|
|||
|
|
|
|||
|
|
# 万箭齐发 (1张)
|
|||
|
|
self.cards.append(Card("万箭齐发", CardType.TRICK, CardSuit.HEART, 1, "所有其他角色需打出【闪】,否则受到1点伤害"))
|
|||
|
|
|
|||
|
|
# 桃园结义 (1张)
|
|||
|
|
self.cards.append(Card("桃园结义", CardType.TRICK, CardSuit.HEART, 1, "所有角色回复1点体力"))
|
|||
|
|
|
|||
|
|
# 五谷丰登 (2张)
|
|||
|
|
for num in [3, 4]:
|
|||
|
|
self.cards.append(Card("五谷丰登", CardType.TRICK, CardSuit.HEART, num, "所有角色依次获得一张牌"))
|
|||
|
|
|
|||
|
|
# 装备牌(简化版,只添加几种)
|
|||
|
|
# 诸葛连弩
|
|||
|
|
self.cards.append(Card("诸葛连弩", CardType.EQUIPMENT, CardSuit.CLUB, 1, "武器,攻击范围1,出牌阶段可以使用任意张【杀】"))
|
|||
|
|
self.cards.append(Card("诸葛连弩", CardType.EQUIPMENT, CardSuit.DIAMOND, 1, "武器,攻击范围1,出牌阶段可以使用任意张【杀】"))
|
|||
|
|
|
|||
|
|
# 青釭剑
|
|||
|
|
self.cards.append(Card("青釭剑", CardType.EQUIPMENT, CardSuit.SPADE, 6, "武器,攻击范围2,无视目标防具"))
|
|||
|
|
|
|||
|
|
# 八卦阵
|
|||
|
|
self.cards.append(Card("八卦阵", CardType.EQUIPMENT, CardSuit.SPADE, 2, "防具,判定为红色时视为使用了【闪】"))
|
|||
|
|
self.cards.append(Card("八卦阵", CardType.EQUIPMENT, CardSuit.CLUB, 2, "防具,判定为红色时视为使用了【闪】"))
|
|||
|
|
|
|||
|
|
# 的卢
|
|||
|
|
self.cards.append(Card("的卢", CardType.EQUIPMENT, CardSuit.CLUB, 5, "+1马,其他角色计算与你的距离+1"))
|
|||
|
|
|
|||
|
|
# 赤兔
|
|||
|
|
self.cards.append(Card("赤兔", CardType.EQUIPMENT, CardSuit.HEART, 5, "-1马,你计算与其他角色的距离-1"))
|
|||
|
|
|
|||
|
|
# 洗牌
|
|||
|
|
self.shuffle()
|
|||
|
|
|
|||
|
|
def shuffle(self):
|
|||
|
|
"""洗牌"""
|
|||
|
|
random.shuffle(self.cards)
|
|||
|
|
logger.info(f"牌堆已洗牌,共 {len(self.cards)} 张牌")
|
|||
|
|
|
|||
|
|
def draw(self, count: int = 1) -> List[Card]:
|
|||
|
|
"""摸牌
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
count: 摸牌数量
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
摸到的牌列表
|
|||
|
|
"""
|
|||
|
|
if len(self.cards) < count:
|
|||
|
|
# 牌不够,将弃牌堆洗入牌堆
|
|||
|
|
self.cards.extend(self.discard_pile)
|
|||
|
|
self.discard_pile.clear()
|
|||
|
|
self.shuffle()
|
|||
|
|
|
|||
|
|
drawn = self.cards[:count]
|
|||
|
|
self.cards = self.cards[count:]
|
|||
|
|
return drawn
|
|||
|
|
|
|||
|
|
def discard(self, cards: List[Card]):
|
|||
|
|
"""弃牌"""
|
|||
|
|
self.discard_pile.extend(cards)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class GeneralPool:
|
|||
|
|
"""武将池"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
"""初始化武将池"""
|
|||
|
|
self.generals: List[General] = []
|
|||
|
|
self._init_standard_generals()
|
|||
|
|
|
|||
|
|
def _init_standard_generals(self):
|
|||
|
|
"""初始化标准武将(简化版)"""
|
|||
|
|
# 刘备
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="刘备",
|
|||
|
|
max_hp=4,
|
|||
|
|
kingdom="蜀",
|
|||
|
|
skills=[
|
|||
|
|
Skill("仁德", "出牌阶段,你可以将任意张手牌交给其他角色,若你给出的牌达到两张或更多,你回复1点体力", "主动"),
|
|||
|
|
Skill("激将", "主公技,当你需要使用或打出【杀】时,你可以令其他蜀势力角色打出一张【杀】(视为由你使用或打出)", "主动")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 关羽
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="关羽",
|
|||
|
|
max_hp=4,
|
|||
|
|
kingdom="蜀",
|
|||
|
|
skills=[
|
|||
|
|
Skill("武圣", "你可以将一张红色牌当【杀】使用或打出", "主动")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 张飞
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="张飞",
|
|||
|
|
max_hp=4,
|
|||
|
|
kingdom="蜀",
|
|||
|
|
skills=[
|
|||
|
|
Skill("咆哮", "锁定技,出牌阶段,你使用【杀】无次数限制", "锁定")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 诸葛亮
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="诸葛亮",
|
|||
|
|
max_hp=3,
|
|||
|
|
kingdom="蜀",
|
|||
|
|
skills=[
|
|||
|
|
Skill("观星", "准备阶段,你可以观看牌堆顶的X张牌(X为存活角色数且至多为5),将任意数量的牌置于牌堆顶,其余的牌置于牌堆底", "主动"),
|
|||
|
|
Skill("空城", "锁定技,当你没有手牌时,你不能成为【杀】或【决斗】的目标", "锁定")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 赵云
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="赵云",
|
|||
|
|
max_hp=4,
|
|||
|
|
kingdom="蜀",
|
|||
|
|
skills=[
|
|||
|
|
Skill("龙胆", "你可以将【杀】当【闪】、【闪】当【杀】使用或打出", "主动")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 曹操
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="曹操",
|
|||
|
|
max_hp=4,
|
|||
|
|
kingdom="魏",
|
|||
|
|
skills=[
|
|||
|
|
Skill("奸雄", "当你受到伤害后,你可以获得对你造成伤害的牌", "主动"),
|
|||
|
|
Skill("护驾", "主公技,当你需要使用或打出【闪】时,你可以令其他魏势力角色打出一张【闪】(视为由你使用或打出)", "主动")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 司马懿
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="司马懿",
|
|||
|
|
max_hp=3,
|
|||
|
|
kingdom="魏",
|
|||
|
|
skills=[
|
|||
|
|
Skill("反馈", "当你受到1点伤害后,你可以获得伤害来源的一张牌", "主动"),
|
|||
|
|
Skill("鬼才", "在任意角色的判定牌生效前,你可以打出一张手牌代替之", "主动")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 夏侯惇
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="夏侯惇",
|
|||
|
|
max_hp=4,
|
|||
|
|
kingdom="魏",
|
|||
|
|
skills=[
|
|||
|
|
Skill("刚烈", "当你受到伤害后,你可以进行判定:若结果不为♥,则伤害来源选择一项:弃置两张手牌,或受到你造成的1点伤害", "主动")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 甄姬
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="甄姬",
|
|||
|
|
max_hp=3,
|
|||
|
|
kingdom="魏",
|
|||
|
|
skills=[
|
|||
|
|
Skill("洛神", "准备阶段,你可以进行判定:当黑色判定牌生效后,你获得之。若结果为黑色,你可以重复此流程", "主动"),
|
|||
|
|
Skill("倾国", "你可以将一张黑色手牌当【闪】使用或打出", "主动")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 孙权
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="孙权",
|
|||
|
|
max_hp=4,
|
|||
|
|
kingdom="吴",
|
|||
|
|
skills=[
|
|||
|
|
Skill("制衡", "出牌阶段限一次,你可以弃置任意张牌,然后摸等量的牌", "主动"),
|
|||
|
|
Skill("救援", "主公技,锁定技,其他吴势力角色对你使用【桃】时,该角色摸一张牌", "锁定")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 周瑜
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="周瑜",
|
|||
|
|
max_hp=3,
|
|||
|
|
kingdom="吴",
|
|||
|
|
skills=[
|
|||
|
|
Skill("英姿", "摸牌阶段,你可以额外摸一张牌", "主动"),
|
|||
|
|
Skill("反间", "出牌阶段限一次,你可以令一名其他角色选择一种花色,然后该角色获得你的一张手牌并展示之,若此牌与所选花色不同,你对其造成1点伤害", "主动")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 吕蒙
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="吕蒙",
|
|||
|
|
max_hp=4,
|
|||
|
|
kingdom="吴",
|
|||
|
|
skills=[
|
|||
|
|
Skill("克己", "若你于出牌阶段内没有使用或打出过【杀】,你可以跳过此回合的弃牌阶段", "主动")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 黄盖
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="黄盖",
|
|||
|
|
max_hp=4,
|
|||
|
|
kingdom="吴",
|
|||
|
|
skills=[
|
|||
|
|
Skill("苦肉", "出牌阶段,你可以失去1点体力,然后摸两张牌", "主动")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 吕布
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="吕布",
|
|||
|
|
max_hp=4,
|
|||
|
|
kingdom="群",
|
|||
|
|
skills=[
|
|||
|
|
Skill("无双", "锁定技,当你使用【杀】指定一个目标后,该角色需依次使用两张【闪】才能抵消此【杀】;当你使用【决斗】指定一个目标后,该角色每次响应此【决斗】需依次打出两张【杀】", "锁定")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 貂蝉
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="貂蝉",
|
|||
|
|
max_hp=3,
|
|||
|
|
kingdom="群",
|
|||
|
|
skills=[
|
|||
|
|
Skill("离间", "出牌阶段限一次,你可以弃置一张牌并选择两名男性角色,后选择的角色视为对先选择的角色使用一张【决斗】(此【决斗】不能被【无懈可击】响应)", "主动"),
|
|||
|
|
Skill("闭月", "结束阶段,你可以摸一张牌", "主动")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
# 华佗
|
|||
|
|
self.generals.append(General(
|
|||
|
|
name="华佗",
|
|||
|
|
max_hp=3,
|
|||
|
|
kingdom="群",
|
|||
|
|
skills=[
|
|||
|
|
Skill("急救", "你的回合外,你可以将一张红色牌当【桃】使用", "主动"),
|
|||
|
|
Skill("青囊", "出牌阶段限一次,你可以弃置一张手牌并令一名角色回复1点体力", "主动")
|
|||
|
|
]
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
def get_random_generals(self, count: int, exclude: List[str] = None) -> List[General]:
|
|||
|
|
"""随机获取武将
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
count: 数量
|
|||
|
|
exclude: 排除的武将名称列表
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
武将列表
|
|||
|
|
"""
|
|||
|
|
available = [g for g in self.generals if not exclude or g.name not in exclude]
|
|||
|
|
if len(available) < count:
|
|||
|
|
return available
|
|||
|
|
return random.sample(available, count)
|
|||
|
|
|
|||
|
|
def get_general_by_name(self, name: str) -> Optional[General]:
|
|||
|
|
"""根据名称获取武将"""
|
|||
|
|
for general in self.generals:
|
|||
|
|
if general.name == name:
|
|||
|
|
return general
|
|||
|
|
return None
|
|||
|
|
|