云剪贴板
云剪贴板 hv93534e
云剪贴板操作
由 dingshengyang 于 2026/01/02 14:29 创建,当前公开。
- 当前快照
- 1 份
- 快照标识符
- @mjwqyocg
- 此快照首次捕获于
- 2026/01/02 18:44 2 个月前
- 此快照最后确认于
- 2026/01/02 18:44 2 个月前
版本 v1.5.3 更新摘要:
- (三氧化硫) 重做:由“指定目标”改为**“全场随机目标”**。强酸的腐蚀是不可控的,使用不当可能误伤友军。
- (铝) 机制优化:移除了“是否驻场”的询问。若环境导致溶解,强制反应并补偿抽牌;若环境适宜,强制进场。
- (氯气) 结算顺序:亡语先增加酸性,再结算AOE伤害(确保伤害享受酸性环境加成)。
- 实时环境响应: 和 的数值现在会在同回合内随环境变化即时刷新。
版本 v1.5.4 更新摘要:
-
后手贴目机制 (Buffer Capacity):为了平衡先手优势,后手玩家 (Player 2) 初始获得 +2 HP 上限与 +2 当前 HP。
-
继承 v1.5.3 所有特性。
Chem-Cards 规则手册 (v1.5.4)
1. 基础规则
1.1 卡牌分类
- [N] 驻场卡 (Normal/Unit):拥有 HP (生命) 和 DP (攻击)。放置在卡槽中战斗。
- [S] 机制卡 (Spell/Mechanism):打出后执行效果,随即进入弃牌堆。
1.2 环境参数
- 酸碱度 [H]:整数范围 。 为酸性, 为碱性, 为中性。
- 氧浓度 [O]:整数范围 。
1.3 核心流程
- 消耗 (Consume):[N]卡攻击敌方本体后,视为耗尽,移出游戏。不触发亡语。
- 死亡 (Die):[N]卡 HP 或被效果销毁(如酸蚀、爆炸)。触发亡语。
- 替换/献祭:卡槽满时打出新卡,旧卡视为死亡,触发亡语。
1.4 游戏区域与配置
- 玩家本体:先手玩家 (Player 1) 初始生命值 (HP) 20,上限 30。后手玩家 (Player 2) 初始获得 +2 HP 上限与 +2 当前 HP,即初始 HP 22,上限 32。HP 0 时判定为负,游戏结束。
- 卡槽:每位玩家拥有 3 个卡槽。
- 手牌与牌堆:游戏开始时,先手抽 6 张,后手抽 6 张。
1.5 流程与动作
1.5.1 出牌 (Play)
- 每回合玩家通常只能打出一张牌(无论 [N] 还是 [S])。
- 替换规则:若卡槽已满(3张),玩家仍可打出新的 [N] 卡。此时必须指定己方场上一张旧卡进行“献祭”(视为死亡,触发亡语),腾出空位放置新卡。
1.5.2 攻击结算 (Combat)
- 单位对战:攻击方 A 选定 敌方 B。
- 过程视为同时发生:,且 。
- 双方卡牌持续进行上述交换,直到一方或双方 HP ,或触发特殊机制(如 的减伤锁血)强制中止。
- HP 的卡牌进入弃牌堆,并触发亡语。
- 直接攻击:若敌方前场无卡,攻击方 A 可攻击敌方本体。
- 敌方本体受到 点伤害(这是防御减免之前的伤害。如果有减免,应考虑减免)。
- 结算后,卡牌 A 视为“消耗”,移入弃牌堆,不触发亡语。
1.5.3 抽牌规则 (Draw)
回合结束阶段,按以下优先级依次结算:
- 卡牌特效:结算回合内打出的抽牌效果(如 )。
- 牌差补偿:若双方“总牌数”(手牌+场上卡牌)差值 ,劣势方(总牌数少的一方)抽 1 张。
- 空手补偿:若某一方手牌数为 0,该方抽 1 张。
1.5.4 弃牌 (Discard)
当效果要求弃牌时,若无特殊指定,由系统随机选择手牌丢弃。
2. 卡牌图鉴 (完整版 v1.5.4)
2.1 基础环境组
- [S]:令 。
- [S]:令 。
- [S]:抽 1 张牌。
- [S]:令 ,并触发两次 效果(抽 2 张)。
2.2 金属与氧化还原组
- [N] () [v1.5.3 重做]:
- 两性反应:打出时立即检测环境。
- 若 :溶解(),玩家抽 1 张牌,卡牌去弃牌堆。
- 若 :溶解(),玩家抽 1 张牌,卡牌去弃牌堆。
- 否则:卡牌进场驻守。
- 两性反应:打出时立即检测环境。
- [N] ():
- 惰性盾牌:在单次单位对攻中,最多受到 3 点伤害(超过部分无效)。
- 物理屏障:己方本体受到的伤害 -2。
- [S]:
- 沉淀/蚀刻:若 ,生成沉淀()。否则,若敌方场上有 ,直接销毁之(同归于尽)。
- [N] () [v1.5.3 机制更新]:
- 亡语:被击败或被效果销毁时(直接攻击对方本体导致的消耗不触发):
- 。
- 对敌方全场(单位+本体)造成 2 点伤害。
- 亡语:被击败或被效果销毁时(直接攻击对方本体导致的消耗不触发):
- [N] () [v1.5.3 实时响应]:
- 强氧化性:攻击力 。攻击力随环境实时变化。
- [N] ():
- 亡语:被击败或被效果销毁时(直接攻击对方本体导致的消耗不触发),对敌方本体造成 4 点伤害,并弃掉敌方 3 张手牌。
2.3 有机与特殊组
- [S]:检视敌方手牌,强制弃掉手中的 。
- [S]:对敌方本体造成 3 点伤害。
- [S]:三选一(需弃一半手牌,向下取整):
-
- 无氧呼吸:触发两次 的效果,本体额外回复 1 点 HP。
-
- 有氧呼吸(需 ):触发六次 的效果(抽6张),本体额外回复 1 点 HP。
-
- 糖原储存:己方本体回复 4 点 HP。
-
2.4 精英/稀有组
- (钒) [N] ():
- 合金:进场时,己方其他金属卡牌 HP上限+2 并回满。
- [N] ():
- 金身:己方本体免疫所有伤害。
- 保值:回合结束时若本卡在场且己方本体 ,回 2 血。
- [N] () [v1.5.3 实时响应]:
- 酸雾:进场时 。
- 氧化酸:基础攻击力 。攻击力随环境实时变化。攻击金属卡牌时 DP+2。
2.5 混乱平衡组 (Chaos Balance)
- [N] ():
- 碱源:进场时 。
- 喷泉:回合结束若环境为碱性(),己方本体回 2 血。
- [N] ():
- 钝化:环境首次变碱性()时,获得永久 +3 HP上限(只触发一次)。
- 酸蚀:回合结束若 ,自身受 3 点伤害。
- [S]:
- 剧烈反应:;己方本体受 1 伤;对敌方随机单位造成 4 伤(若空场则对本体 3 伤)。
- [S] [v1.5.3 重做]:
- 酸雨:打出后,。
- 无差别脱水:系统从全场所有存活单位(包含己方和敌方)中随机选择一个,对其造成 4 点伤害。
- 溅射:若该单位被此伤害击杀,其持有者受到 2 点溅射伤害。
Chem-Cards 电子裁判代码 (v1.5.4)
请保存为
PYTHONchem_cards_referee_v1.5.4.py。import random
import math
# ==========================================
# 基础架构类
# ==========================================
class Card:
def __init__(self, name, card_type, hp=0, dp=0, desc=""):
self.name = name
self.type = card_type # 'N' (Normal) or 'S' (Special)
self.max_hp = hp
self.hp = hp
self._base_dp = dp
self._dp = dp
self.desc = desc
self.is_metal = False
@property
def dp(self):
return self._dp
@dp.setter
def dp(self, value):
self._dp = value
def reset_stats(self):
self.hp = self.max_hp
self._dp = self._base_dp
def __str__(self):
if self.type == 'N':
return f"[{self.name} HP:{self.hp}/{self.max_hp} DP:{self.dp}]"
return f"[{self.name} (S)]"
# --- 生命周期钩子 ---
def on_play(self, game, player, opponent):
"""S卡打出时的效果"""
pass
def on_deploy(self, game, player):
"""N卡进场效果 (战吼)"""
pass
def on_death(self, game, player, opponent):
"""亡语:被移除/销毁时触发。"""
pass
def on_board_effect(self, game, player, dmg):
"""伤害拦截/减免"""
return dmg
def on_turn_end(self, game, player):
"""回合结束效果"""
pass
def update_continuous_state(self, game):
"""状态更新:环境改变时立即调用"""
pass
# ==========================================
# 具体卡牌实现 (v1.5.3 标准)
# ==========================================
# --- 基础环境组 ---
class Card_H_Plus(Card):
def __init__(self):
super().__init__("H⁺", 'S', desc="环境 [H] + 1")
def on_play(self, game, player, opponent):
game.modify_h(1)
class Card_OH_Minus(Card):
def __init__(self):
super().__init__("OH⁻", 'S', desc="环境 [H] - 1")
def on_play(self, game, player, opponent):
game.modify_h(-1)
class Card_H2O(Card):
def __init__(self):
super().__init__("H₂O", 'S', desc="抽一张牌")
def on_play(self, game, player, opponent):
print(f"系统: 💧 {self.name} 润泽,抽牌。")
game.player_draw(player, 1)
class Card_H2O2(Card):
def __init__(self):
super().__init__("H₂O₂", 'S', desc="抽两张牌; [O]+1")
def on_play(self, game, player, opponent):
print(f"系统: {self.name} 分解!环境 [O] + 1,并发动双倍水效。")
game.modify_o(1)
game.player_draw(player, 2)
# --- 金属与氧化还原组 ---
class Card_Al(Card):
def __init__(self):
super().__init__("Al", 'N', hp=5, dp=3, desc="强酸/强碱自动溶解抽1牌")
self.is_metal = True
def on_play(self, game, player, opponent):
"""Al卡打出时的处理"""
pass
def check_reaction_and_result(self, game, player):
"""
自动判定,自动抽牌。
返回 True 表示已反应并处理完毕(不进场)。
"""
if game.H <= -4:
print(f"系统: 🧪 {self.name} 在强碱环境([H]={game.H})下溶解生成偏铝酸根!")
print("-> 环境 [H] + 4")
game.modify_h(4)
print("-> 反应产物回收:玩家抽 1 张牌。")
game.player_draw(player, 1)
return True
elif game.H >= 3:
print(f"系统: 🧪 {self.name} 在酸性环境([H]={game.H})下溶解生成铝离子!")
print("-> 环境 [H] - 3")
game.modify_h(-3)
print("-> 反应产物回收:玩家抽 1 张牌。")
game.player_draw(player, 1)
return True
return False
class Card_Cu(Card):
def __init__(self):
super().__init__("Cu", 'N', hp=8, dp=2, desc="单轮锁血3; 本体减伤2")
self.is_metal = True
def on_board_effect(self, game, player, dmg):
reduced = max(0, dmg - 2)
if dmg > 0 and reduced < dmg:
print(f"系统: 🛡️ {self.name} 物理屏障,伤害 {dmg} -> {reduced}")
return reduced
class Card_Fe3_Plus(Card):
def __init__(self):
super().__init__("Fe³⁺", 'S', desc="H<=-3沉淀; 遇Cu同归于尽")
def on_play(self, game, player, opponent):
if game.H <= -3:
print(f"系统: {self.name} 在碱性环境([H]={game.H})下生成红褐色沉淀![H] + 3。")
game.modify_h(3)
return
cu_indices = [i for i, c in enumerate(opponent.slots) if c and isinstance(c, Card_Cu)]
if cu_indices:
idx = cu_indices[0]
target_cu = opponent.slots[idx]
print(f"系统: 🧪 {self.name} 蚀刻了 {target_cu.name}!双方同归于尽。")
opponent.remove_slot_card(idx, game, trigger_deathrattle=True)
else:
print(f"系统: {self.name} 缺乏反应条件,无效挥发。")
class Card_Cl2(Card):
def __init__(self):
super().__init__("Cl₂", 'N', hp=2, dp=3, desc="亡语: [H]+1 & 全场AOE 2")
def on_death(self, game, player, opponent):
print(f"系统: ☠️ {self.name} 亡语触发!")
# 先改环境,确保AOE伤害可能享受环境加成
print("-> 气体水解,环境 [H] + 1。")
game.modify_h(1)
dmg = 2
print(f"-> 毒气扩散!对敌方全员造成 {dmg} 点伤害。")
# 攻击敌方单位
for i in range(3):
c = opponent.slots[i]
if c:
prev_hp = c.hp
c.hp -= dmg
print(f" 蚀刻 {c.name}: {prev_hp} -> {c.hp}")
if c.hp <= 0:
print(f" 💀 {c.name} 被摧毁!")
opponent.remove_slot_card(i, game, trigger_deathrattle=True)
# 攻击敌方本体
final_dmg = game.calc_damage_mitigation(opponent, dmg)
if final_dmg > 0:
opponent.hp -= final_dmg
print(f" 敌方本体受到 {final_dmg} 点毒气伤害。")
else:
print(" 敌方本体免疫了毒气伤害。")
class Card_MnO4_Minus(Card):
def __init__(self):
super().__init__("MnO₄⁻", 'N', hp=2, dp=2, desc="DP = 2 + [H]")
def update_continuous_state(self, game):
# 动态更新:DP = 2 + max(0, H)
base = 2
bonus = game.H if game.H > 0 else 0
new_dp = base + bonus
if self.dp != new_dp:
self.dp = new_dp
class Card_F2(Card):
def __init__(self):
super().__init__("F₂", 'N', hp=2, dp=5, desc="亡语: 敌方本体4伤+弃3牌")
def on_death(self, game, player, opponent):
print(f"系统: ☢️ {self.name} 亡语爆发!")
dmg = 4
final_dmg = game.calc_damage_mitigation(opponent, dmg)
if final_dmg > 0:
opponent.hp -= final_dmg
print(f"-> 氟气重创敌方本体,造成 {final_dmg} 点伤害!")
discard_cnt = min(3, len(opponent.hand))
if discard_cnt > 0:
print(f"-> 氟气迫使敌方弃掉 {discard_cnt} 张牌。")
for _ in range(discard_cnt):
if not opponent.hand: break
idx = random.randint(0, len(opponent.hand)-1)
c = opponent.hand.pop(idx)
game.discard_pile.append(c)
# --- 有机与特殊组 ---
class Card_SCN_Minus(Card):
def __init__(self):
super().__init__("SCN⁻", 'S', desc="针对 Fe3+ 弃牌")
def on_play(self, game, player, opponent):
fe_indices = [i for i, c in enumerate(opponent.hand) if isinstance(c, Card_Fe3_Plus)]
n = len(fe_indices)
if n > 0:
discard_cnt = 1 if n == 1 else n - 1
print(f"系统: 检测到敌方手中有 {n} 张 Fe3+,络合反应迫使其丢弃 {discard_cnt} 张!")
to_discard_indices = fe_indices[:discard_cnt]
for idx in sorted(to_discard_indices, reverse=True):
card = opponent.hand.pop(idx)
game.discard_pile.append(card)
print(f"-> 敌方丢弃了 {card.name}")
else:
print("系统: 敌方手中未检出 Fe3+。")
class Card_C2H5OH(Card):
def __init__(self):
super().__init__("C₂H₅OH", 'S', desc="对敌方造成 3 点伤害")
def on_play(self, game, player, opponent):
self.apply_effect(game, opponent)
def apply_effect(self, game, target_player):
raw_dmg = 3
print(f"系统: 🍺 {self.name} 造成醉酒伤害。")
final_dmg = game.calc_damage_mitigation(target_player, raw_dmg)
if final_dmg > 0:
target_player.hp -= final_dmg
print(f"-> 敌方受到 {final_dmg} 点伤害!")
class Card_C6H12O6(Card):
def __init__(self):
super().__init__("C₆H₁₂O₆", 'S', desc="代谢抉择; 弃一半手牌")
def on_play(self, game, player, opponent):
print(f"\n[{self.name} 代谢路径选择]")
print("1. 无氧呼吸 (2次乙醇伤害)")
can_aerobic = (game.O >= 6)
opt2_str = "2. 有氧呼吸 (抽6张牌)" if can_aerobic else "2. [不可用] 有氧呼吸 (需 [O] >= 6)"
print(opt2_str)
print("3. 糖原储存 (HP + 4)")
valid_choices = ['1', '3']
if can_aerobic: valid_choices.append('2')
choice = ''
while choice not in valid_choices:
choice = input(f"请输入选项 ({'/'.join(valid_choices)}): ").strip()
did_respire = False
if choice == '1':
print("系统: 进行无氧呼吸发酵...")
eff = Card_C2H5OH()
eff.apply_effect(game, opponent)
eff.apply_effect(game, opponent)
did_respire = True
elif choice == '2':
print("系统: 进行高效有氧呼吸...")
game.player_draw(player, 6)
did_respire = True
elif choice == '3':
print("系统: 转化为糖原储备,回复 4 HP。")
player.heal(4)
if did_respire:
print("系统: 呼吸作用提供能量,额外回复 1 HP。")
player.heal(1)
cnt = math.floor(len(player.hand) / 2)
if cnt > 0:
print(f"系统: 代谢产物堆积,随机丢弃 {cnt} 张手牌。")
for _ in range(cnt):
if not player.hand: break
idx = random.randint(0, len(player.hand)-1)
c = player.hand.pop(idx)
game.discard_pile.append(c)
print(f"-> 丢弃了 {c.name}")
# --- 精英/稀有卡 ---
class Card_V(Card):
def __init__(self):
super().__init__("V", 'N', hp=7, dp=3, desc="战吼: 强化其他金属")
self.is_metal = True
def on_deploy(self, game, player):
print(f"系统: 🏗️ {self.name} 进场,添加合金元素!")
found = False
for c in player.slots:
if c and c != self and c.is_metal:
c.max_hp += 2
c.hp = c.max_hp # 回满
print(f"-> {c.name} 获得强化! (HP:{c.hp}/{c.max_hp})")
found = True
if not found:
print("-> 场上无其他金属单质可强化。")
class Card_Au(Card):
def __init__(self):
super().__init__("Au", 'N', hp=6, dp=2, desc="本体免疫; 回合末回血")
self.is_metal = True
def on_board_effect(self, game, player, dmg):
if dmg > 0:
print(f"系统: 🌟 {self.name} 黄金屏障!伤害 {dmg} 被完全免疫!")
return 0
def on_turn_end(self, game, player):
if player.hp < 24:
print(f"系统: ✨ {self.name} 储备增值,回复 2 HP。")
player.heal(2)
class Card_HNO3(Card):
def __init__(self):
super().__init__("HNO₃", 'N', hp=5, dp=2, desc="战吼:[H]+1; 对金属伤害+2")
def on_deploy(self, game, player):
print(f"系统: ⚗️ {self.name} 挥发酸雾!")
game.modify_h(1)
def update_continuous_state(self, game):
new_dp = max(2, 1 + game.H)
if self.dp != new_dp:
self.dp = new_dp
# --- 混乱平衡组 ---
class Card_NH3(Card):
def __init__(self):
super().__init__("NH₃", 'N', hp=3, dp=2, desc="碱性源; 碱性环境回血")
def on_deploy(self, game, player):
print(f"系统: 💨 {self.name} 释放,环境碱性增强。")
game.modify_h(-1)
def on_turn_end(self, game, player):
if game.H < 0:
print(f"系统: ⛲ {self.name} 触发喷泉效应,本体回复 2 HP。")
player.heal(2)
class Card_Mg(Card):
def __init__(self):
super().__init__("Mg", 'N', hp=5, dp=3, desc="碱性钝化(+3HP); 强酸受损")
self.is_metal = True
self._buffed = False
def update_continuous_state(self, game):
# 钝化膜是一次性生成的永久Buff
if game.H < 0 and not self._buffed:
self._buffed = True
self.max_hp += 3
self.hp += 3
print(f"系统: 🛡️ {self.name} 在碱性环境中生成致密钝化膜!HP上限+3 (当前 {self.hp}/{self.max_hp})。")
def on_turn_end(self, game, player):
if game.H >= 3:
dmg = 3
print(f"系统: 🧪 {self.name} 在强酸([H]={game.H})中剧烈反应,受到 {dmg} 点腐蚀伤害!")
self.hp -= dmg
if self.hp <= 0:
print(f"-> {self.name} 溶解殆尽。")
try:
idx = player.slots.index(self)
player.remove_slot_card(idx, game, trigger_deathrattle=True)
except ValueError:
pass
class Card_Na(Card):
def __init__(self):
super().__init__("Na", 'S', desc="[H]-1; 自伤1; 随机敌方4伤")
def on_play(self, game, player, opponent):
print(f"系统: 💥 {self.name} 投入水中!剧烈反应!")
game.modify_h(-1)
print(f"-> ⚠️ 爆炸波及操作者!己方本体受到 1 点伤害。")
player.hp -= 1
targets = [i for i, c in enumerate(opponent.slots) if c]
if targets:
target_idx = random.choice(targets)
target_card = opponent.slots[target_idx]
dmg = 4
print(f"-> 爆炸随机命中了敌方卡牌 {target_card.name},造成 {dmg} 点伤害!")
target_card.hp -= dmg
if target_card.hp <= 0:
print(f" {target_card.name} 被炸毁!")
opponent.remove_slot_card(target_idx, game, trigger_deathrattle=True)
else:
dmg = 3
print(f"-> 敌方空场,爆炸直击敌方本体,造成 {dmg} 点伤害!")
final_dmg = game.calc_damage_mitigation(opponent, dmg)
if final_dmg > 0:
opponent.hp -= final_dmg
class Card_SO3(Card):
def __init__(self):
super().__init__("SO₃", 'S', desc="[H]+2; 全场随机1单位4伤(击杀溅射2)")
def on_play(self, game, player, opponent):
# 1. 环境改变
print(f"系统: ☁️ {self.name} 排放,形成酸雨!环境 [H] + 2。")
game.modify_h(2)
# 2. 收集全场所有目标
targets = []
for i, c in enumerate(player.slots):
if c: targets.append((player, i, c))
for i, c in enumerate(opponent.slots):
if c: targets.append((opponent, i, c))
if not targets:
print("系统: 场上空无一物,酸液滴落在空地上无效。")
return
print("系统: 🎲 酸雨无差别坠落中...")
target_owner, idx, target_card = random.choice(targets)
dmg = 4
print(f"-> 命中!酸液滴落在 {target_owner.name} 的 {target_card.name} 上,造成 {dmg} 点脱水伤害!")
target_card.hp -= dmg
# 3. 击杀判定与溅射
if target_card.hp <= 0:
print(f" 💀 {target_card.name} 被彻底碳化销毁!")
# 触发亡语
target_owner.remove_slot_card(idx, game, trigger_deathrattle=True)
# 溅射伤害:谁的卡死了,谁的本体受溅射
print(f"-> 💧 强酸飞溅!{target_owner.name} 本体受到 2 点溅射伤害。")
target_owner.hp -= 2
else:
print(f" {target_card.name} 幸存 (剩余 HP:{target_card.hp})。")
# ==========================================
# 游戏核心逻辑
# ==========================================
class Player:
def __init__(self, name, hp=20, max_hp=30):
self.name = name
self.hp = hp
self.max_hp = max_hp
self.slots = [None, None, None]
self.hand = []
def is_alive(self):
return self.hp > 0
def heal(self, amt):
prev = self.hp
self.hp = min(self.max_hp, self.hp + amt)
print(f"-> {self.name} 回复 {amt} HP ({prev} -> {self.hp})")
def remove_slot_card(self, idx, game, trigger_deathrattle=True):
card = self.slots[idx]
if card:
self.slots[idx] = None
if trigger_deathrattle:
opponent = game.p2 if self == game.p1 else game.p1
card.on_death(game, self, opponent)
else:
print(f"ℹ️ {card.name} 离场 (无亡语)。")
game.discard_pile.append(card)
def count_cards(self):
return len(self.hand) + sum(1 for c in self.slots if c)
class Game:
def __init__(self):
self.H = 0
self.O = 0
self.deck = []
self.discard_pile = []
# v1.5.4 Komi (贴目) 设定
# P1 先手,标准数值
self.p1 = Player("Player 1", hp=20, max_hp=30)
# P2 后手,获得 HP+2/MaxHP+2 补偿
self.p2 = Player("Player 2", hp=22, max_hp=32)
self.current_player = None
self.init_deck()
def modify_h(self, val):
self.H += val
if self.H > 6: self.H = 6
if self.H < -6: self.H = -6
state = "酸性" if self.H > 0 else ("碱性" if self.H < 0 else "中性")
print(f"== 环境变更: [H] = {self.H} ({state}) ==")
self.update_field_stats()
def modify_o(self, val):
self.O += val
if self.O < 0: self.O = 0
print(f"== 环境变更: [O] = {self.O} ==")
def init_deck(self):
composition = [
(Card_H_Plus, 6),
(Card_OH_Minus, 10),
(Card_H2O, 12),
(Card_H2O2, 7),
(Card_SO3, 4),
(Card_Al, 6),
(Card_Cu, 6),
(Card_Cl2, 6),
(Card_MnO4_Minus, 6),
(Card_V, 3),
(Card_Au, 3),
(Card_HNO3, 5),
(Card_Fe3_Plus, 5),
(Card_SCN_Minus, 4),
(Card_C2H5OH, 5),
(Card_C6H12O6, 5),
(Card_F2, 4),
(Card_NH3, 5),
(Card_Mg, 5),
(Card_Na, 5)
]
self.deck = []
for cls, cnt in composition:
for _ in range(cnt):
self.deck.append(cls())
random.shuffle(self.deck)
print(f"牌堆初始化完成: 共 {len(self.deck)} 张牌。")
def draw(self):
if not self.deck:
if not self.discard_pile:
print("!! 警告: 牌堆与弃牌堆均耗尽 !!")
return None
print(">> 牌堆耗尽,重洗弃牌堆...")
self.deck = self.discard_pile[:]
self.discard_pile = []
random.shuffle(self.deck)
for c in self.deck: c.reset_stats()
return self.deck.pop()
def player_draw(self, player, num):
for _ in range(num):
c = self.draw()
if c:
player.hand.append(c)
print(f"{player.name} 抽了一张牌。")
def update_field_stats(self):
"""全场状态刷新"""
for p in [self.p1, self.p2]:
for c in p.slots:
if c:
c.update_continuous_state(self)
def calc_damage_mitigation(self, target_player, raw_dmg):
final_dmg = raw_dmg
for c in target_player.slots:
if c and isinstance(c, Card_Au):
return c.on_board_effect(self, target_player, raw_dmg)
for c in target_player.slots:
if c and final_dmg > 0:
final_dmg = c.on_board_effect(self, target_player, final_dmg)
return final_dmg
def start(self):
print("\n=== Chem-Cards v1.5.4 Referee System (Komi Update) ===")
print("Update: Player 2 (后手) receives +2 Initial HP and +2 Max HP Komi.")
print(f"P1 (先手) HP: {self.p1.hp}/{self.p1.max_hp}")
print(f"P2 (后手) HP: {self.p2.hp}/{self.p2.max_hp}")
self.player_draw(self.p1, 6)
self.player_draw(self.p2, 6)
self.current_player = self.p1
turn_num = 1
while self.p1.is_alive() and self.p2.is_alive():
print(f"\n>>> 第 {turn_num} 回合 - {self.current_player.name} 行动 <<<")
self.play_turn()
self.current_player = self.p2 if self.current_player == self.p1 else self.p1
turn_num += 1
winner = self.p1.name if self.p1.is_alive() else self.p2.name
print(f"\n*** 游戏结束! 获胜者: {winner} ***")
def print_status(self):
opp = self.p2 if self.current_player == self.p1 else self.p1
curr = self.current_player
print(f"\n[环境] H:{self.H} | O:{self.O}")
print(f"--- 敌方 ({opp.name}) HP:{opp.hp}/{opp.max_hp} 手牌:{len(opp.hand)} ---")
slots = []
for c in opp.slots:
if c: slots.append(f"[{c.name} {c.hp}/{c.dp}]")
else: slots.append("[_]")
print(f"敌方前场: {' '.join(slots)}")
print("-" * 30)
slots = []
for c in curr.slots:
if c: slots.append(f"[{c.name} {c.hp}/{c.dp}]")
else: slots.append("[_]")
print(f"我方前场: {' '.join(slots)}")
print(f"--- 我方 ({curr.name}) HP:{curr.hp}/{curr.max_hp} ---")
print("我方手牌:")
for i, c in enumerate(curr.hand):
print(f" {i}: {c.name} | {c.desc}")
def play_turn(self):
self.update_field_stats()
self.print_status()
player = self.current_player
opponent = self.p2 if player == self.p1 else self.p1
# 1. 出牌阶段
has_played = False
while not has_played:
print("\n指令: play <序号> | skip")
raw_input = input("> ").strip().lower().split()
if not raw_input: continue
cmd = raw_input[0]
if cmd == 'skip':
has_played = True
print("玩家选择跳过出牌。")
elif cmd == 'play':
if len(raw_input) < 2:
print("错误: 请输入手牌序号。")
continue
try:
idx = int(raw_input[1])
if 0 <= idx < len(player.hand):
card = player.hand.pop(idx)
self.handle_card_played(player, opponent, card)
has_played = True
else:
print("错误: 序号超出范围。")
except ValueError:
print("错误: 序号格式无效。")
self.update_field_stats()
# 2. 攻击阶段
print("\n进入攻击阶段。指令: atk <我方槽位> <敌方槽位/face> | end")
attacked_indices = set()
while True:
raw_input = input("⚔️ > ").strip().lower().split()
if not raw_input: continue
cmd = raw_input[0]
if cmd == 'end': break
if cmd == 'atk' and len(raw_input) == 3:
try:
my_idx = int(raw_input[1])
target_str = raw_input[2]
if not (0 <= my_idx < 3):
print("错误: 我方槽位无效。")
continue
if my_idx in attacked_indices:
print("提示: 该单位本回合已攻击过。")
continue
my_card = player.slots[my_idx]
if not my_card:
print("错误: 该槽位为空。")
continue
if target_str == 'face':
if any(c for c in opponent.slots if c):
print("阻挡: 敌方前场有单位,无法直接攻击本体!")
continue
self.combat_face(player, opponent, my_idx)
else:
target_idx = int(target_str)
if not (0 <= target_idx < 3):
print("错误: 敌方槽位无效。")
continue
target_card = opponent.slots[target_idx]
if not target_card:
print("错误: 敌方槽位为空。")
continue
self.combat_unit(player, opponent, my_idx, target_idx)
if player.slots[my_idx]:
attacked_indices.add(my_idx)
except ValueError:
print("错误: 参数格式应为数字。")
else:
print("未知指令。")
# 3. 回合结束
print("\n--- 回合结束结算 ---")
for i in range(3):
c = player.slots[i]
if c:
c.on_turn_end(self, player)
# 4. 抽牌检查
self.check_end_draw(player, opponent)
def handle_card_played(self, player, opponent, card):
print(f"✨ 玩家打出了 {card.name}")
if card.type == 'S':
card.on_play(self, player, opponent)
self.discard_pile.append(card)
else:
# v1.5.3 Logic: Al 的特殊逻辑
if isinstance(card, Card_Al):
reacted = card.check_reaction_and_result(self, player)
if reacted:
self.discard_pile.append(card)
return
slot_idx = -1
empty_slots = [i for i, c in enumerate(player.slots) if c is None]
if empty_slots:
slot_idx = empty_slots[0]
player.slots[slot_idx] = card
print(f"-> 部署在槽位 {slot_idx}")
else:
print(f"⚠️ 卡槽已满: {[c.name for c in player.slots]}")
while True:
try:
rep = int(input("请选择献祭的槽位 (0-2): "))
if 0 <= rep <= 2:
print(f"-> 献祭了旧卡,部署新卡。")
player.remove_slot_card(rep, self, trigger_deathrattle=True)
player.slots[rep] = card
slot_idx = rep
break
except ValueError: pass
card.on_deploy(self, player)
card.update_continuous_state(self)
def combat_face(self, attacker, defender, slot_idx):
card = attacker.slots[slot_idx]
raw_dmg = card.dp
print(f"⚔️ {card.name} 突袭敌方本体!基础伤害: {raw_dmg}")
final_dmg = self.calc_damage_mitigation(defender, raw_dmg)
if final_dmg > 0:
defender.hp -= final_dmg
print(f"-> 命中!敌方 HP -{final_dmg} (剩余 {defender.hp})")
else:
print(f"-> 攻击无效 (被阻挡/免疫)。")
print(f"ℹ️ 规则: {card.name} 攻击本体后消耗 (不触发亡语)。")
attacker.remove_slot_card(slot_idx, self, trigger_deathrattle=False)
def combat_unit(self, p1, p2, idx1, idx2):
c1 = p1.slots[idx1]
c2 = p2.slots[idx2]
print(f"⚔️ 对攻: {c1.name} vs {c2.name}")
is_c1_cu = isinstance(c1, Card_Cu)
is_c2_cu = isinstance(c2, Card_Cu)
round_dmg_c1 = 0
round_dmg_c2 = 0
while c1.hp > 0 and c2.hp > 0:
d1_final = c2.dp
d2_final = c1.dp
if isinstance(c2, Card_HNO3) and c1.is_metal: d1_final += 2
if isinstance(c1, Card_HNO3) and c2.is_metal: d2_final += 2
c1.hp -= d1_final
c2.hp -= d2_final
round_dmg_c1 += d1_final
round_dmg_c2 += d2_final
stop = False
if is_c1_cu and round_dmg_c1 > 3:
c1.hp += (round_dmg_c1 - 3)
stop = True
if is_c2_cu and round_dmg_c2 > 3:
c2.hp += (round_dmg_c2 - 3)
stop = True
if stop: break
print(f"结算: {c1.name}({c1.hp}) | {c2.name}({c2.hp})")
if c1.hp <= 0:
print(f"-> {c1.name} 战败。")
p1.remove_slot_card(idx1, self, trigger_deathrattle=True)
if c2.hp <= 0:
print(f"-> {c2.name} 战败。")
p2.remove_slot_card(idx2, self, trigger_deathrattle=True)
def check_end_draw(self, current, opponent):
cnt_cur = current.count_cards()
cnt_opp = opponent.count_cards()
diff = abs(cnt_cur - cnt_opp)
if diff > 2:
dis = current if cnt_cur < cnt_opp else opponent
print(f"⚖️ 牌差补偿: {dis.name} 处于劣势,抽 1 张牌。")
self.player_draw(dis, 1)
if not current.hand:
self.player_draw(current, 1)
if not opponent.hand:
self.player_draw(opponent, 1)
if __name__ == "__main__":
g = Game()
g.start()