From 199cc0f13380ef92b6d206deadc8e02d330832df Mon Sep 17 00:00:00 2001 From: Flick <79459207+flick-ai@users.noreply.github.com> Date: Wed, 5 Jun 2024 03:34:01 +0800 Subject: [PATCH] finish 4.7 support card --- genius_invocation/card/action/base.py | 1 + .../event/arcane_legend/Joyous_Celebration.py | 2 +- .../action/support/companion/SirArthur.py | 60 +++++++++ .../card/action/support/item/Kusava.py | 89 +++++++++++++ .../location/CentralLaboratoryRuins.py | 58 +++++++++ .../support/location/Fortress_of_Meropide.py | 4 +- .../location/TheMausoleumofKingDeshret.py | 122 ++++++++++++++++++ genius_invocation/game/game.py | 4 +- genius_invocation/game/player.py | 12 +- genius_invocation/game/zone.py | 31 ++++- uncompleted.txt | 6 +- 11 files changed, 370 insertions(+), 19 deletions(-) create mode 100644 genius_invocation/card/action/support/companion/SirArthur.py create mode 100644 genius_invocation/card/action/support/item/Kusava.py create mode 100644 genius_invocation/card/action/support/location/CentralLaboratoryRuins.py create mode 100644 genius_invocation/card/action/support/location/TheMausoleumofKingDeshret.py diff --git a/genius_invocation/card/action/base.py b/genius_invocation/card/action/base.py index 24bb83ad..fab73c4a 100644 --- a/genius_invocation/card/action/base.py +++ b/genius_invocation/card/action/base.py @@ -13,6 +13,7 @@ class ActionCard: cost_num: int cost_type: CostType card_type: ActionCardType + can_tune: bool = True def on_played(self, game: 'GeniusGame') -> None: ''' diff --git a/genius_invocation/card/action/event/arcane_legend/Joyous_Celebration.py b/genius_invocation/card/action/event/arcane_legend/Joyous_Celebration.py index b0e6b932..0de3758b 100644 --- a/genius_invocation/card/action/event/arcane_legend/Joyous_Celebration.py +++ b/genius_invocation/card/action/event/arcane_legend/Joyous_Celebration.py @@ -9,7 +9,7 @@ class Joyous_Celebration(ActionCard): id: int = 330003 name = "Joyous Celebration" name_ch = "愉舞欢游" - cost_num = 1 + cost_num = 0 cost_type = CostType.WHITE card_type = ActionCardType.EVENT_ARCANE_LEGEND def __init__(self) -> None: diff --git a/genius_invocation/card/action/support/companion/SirArthur.py b/genius_invocation/card/action/support/companion/SirArthur.py new file mode 100644 index 00000000..56e690f7 --- /dev/null +++ b/genius_invocation/card/action/support/companion/SirArthur.py @@ -0,0 +1,60 @@ +from genius_invocation.utils import * +from genius_invocation.card.action.support.base import SupportCard +from genius_invocation.card.action.base import ActionCard +from typing import TYPE_CHECKING +from genius_invocation.entity.support import Support +from genius_invocation.entity.status import Combat_Status +from copy import deepcopy + +if TYPE_CHECKING: + from genius_invocation.game.game import GeniusGame + from genius_invocation.game.player import GeniusPlayer + +class SirArthurEntity(Support): + name: str = 'Sir Arthur' + name_ch = '亚瑟先生' + max_count = 2 + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character=None): + super().__init__(game, from_player, from_character) + self.news_lead = 0 + + def on_tune_card(self, game: 'GeniusGame'): + if game.active_player_index == self.from_player.index: + self.news_lead = min(self.max_count, self.news_lead + 1) + + def on_discard_card(self, game: 'GeniusGame'): + if game.active_player_index == self.from_player.index: + self.news_lead = min(self.max_count, self.news_lead + 1) + + def on_end(self, game: 'GeniusGame'): + if game.active_player_index == self.from_player.index: + if self.news_lead == self.max_count: + self.news_lead = 0 + card = get_opponent(game).card_zone.card[0] + self.from_player.hand_zone.add([deepcopy(card)]) + + def update_listener_list(self): + self.listeners = [ + (EventType.ON_TUNE_CARD, ZoneType.SUPPORT_ZONE, self.on_tune_card), + (EventType.ON_DISCARD_CARD, ZoneType.SUPPORT_ZONE, self.on_discard_card), + (EventType.END_PHASE, ZoneType.SUPPORT_ZONE, self.on_end), + ] + +class SirArthur(SupportCard): + id: int = 322026 + name: str = 'Sir Arthur' + name_ch = '亚瑟先生' + cost_num = 0 + cost_type = None + card_type = ActionCardType.SUPPORT_COMPANION + + def __init__(self) -> None: + super().__init__() + self.entity = None + + def on_played(self, game: 'GeniusGame') -> None: + self.entity = SirArthurEntity(game, from_player=game.active_player) + super().on_played(game) + + + diff --git a/genius_invocation/card/action/support/item/Kusava.py b/genius_invocation/card/action/support/item/Kusava.py new file mode 100644 index 00000000..552728a1 --- /dev/null +++ b/genius_invocation/card/action/support/item/Kusava.py @@ -0,0 +1,89 @@ +from genius_invocation.utils import * +from genius_invocation.card.action.support.base import SupportCard +from typing import TYPE_CHECKING +from genius_invocation.entity.support import Support + +if TYPE_CHECKING: + from genius_invocation.game.game import GeniusGame + from genius_invocation.game.player import GeniusPlayer + + +class KusavaEntity(Support): + name: str = 'Kusava' + name_ch = '苦舍桓' + max_count = 2 + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character=None): + super().__init__(game, from_player, from_character) + self.memories_and_dreams = 0 + + def get_max_count_card(self, game: 'GeniusGame'): + max_count = 0 + max_idx = [] + for idx, action_card in enumerate(self.from_player.hand_zone.card): + if action_card.card_type == ActionCardType.EQUIPMENT_TALENT: + count = sum([i['cost_num'] for i in action_card.cost]) + else: + count = action_card.cost_num + + if count > max_count: + max_idx = [] + max_count = count + max_idx.append(idx) + if count == max_count: + max_idx.append(idx) + return idx + + def on_begin(self, game:'GeniusGame'): + if game.active_player_index == self.from_player.index: + max_count_idx = self.get_max_count_card(game) + if len(max_count_idx) == 0: + return + if len(max_count_idx) > 2: + max_count_idx = max_count_idx[0:2] + + for idx in max_count_idx: + self.from_player.hand_zone.discard_card(idx) + self.memories_and_dreams = min(self.max_count, self.memories_and_dreams + 1) + + def on_calculate_dice(self, game: 'GeniusGame') -> bool: + if game.active_player_index == self.from_player.index: + if game.current_dice.use_type in SkillType: + if self.from_player.round_play_cards == 0: + if self.memories_and_dreams > 0: + if game.current_dice.cost[0]['cost_num'] > 0: + game.current_dice.cost[0]['cost_num'] -= 1 + return True + if len(game.current_dice.cost) > 1: + if game.current_dice.cost[1]['cost_num'] > 0: + game.current_dice.cost[1]['cost_num'] -= 1 + return True + return False + + def on_skill(self, game: 'GeniusGame') -> None: + if self.on_calculate_dice(game): + self.memories_and_dreams -= 1 + + def update_listener_list(self): + self.listeners = [ + (EventType.ON_USE_SKILL, ZoneType.SUPPORT_ZONE, self.on_skill), + (EventType.CALCULATE_DICE, ZoneType.SUPPORT_ZONE, self.on_calculate_dice), + (EventType.BEGIN_ACTION_PHASE, ZoneType.SUPPORT_ZONE, self.on_begin), + ] + def show(self): + return str(self.usage) + +class Kusava(SupportCard): + id: int = 323008 + name: str = 'Kusava' + name_ch = '苦舍桓' + cost_num = 0 + cost_type = None + card_type = ActionCardType.SUPPORT_ITEM + + def __init__(self) -> None: + super().__init__() + self.entity = None + + def on_played(self, game: 'GeniusGame') -> None: + self.entity = KusavaEntity(game, from_player=game.active_player) + super().on_played(game) diff --git a/genius_invocation/card/action/support/location/CentralLaboratoryRuins.py b/genius_invocation/card/action/support/location/CentralLaboratoryRuins.py new file mode 100644 index 00000000..40d4a851 --- /dev/null +++ b/genius_invocation/card/action/support/location/CentralLaboratoryRuins.py @@ -0,0 +1,58 @@ +from genius_invocation.utils import * +from genius_invocation.card.action.support.base import SupportCard +from typing import TYPE_CHECKING +from genius_invocation.entity.support import Support + +if TYPE_CHECKING: + from genius_invocation.game.game import GeniusGame + from genius_invocation.game.player import GeniusPlayer + + +class CentralLaboratoryRuinsEntity(Support): + name = 'Central Laboratory Ruins' + name_ch = '中央实验室遗址' + max_usage = 9 + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character=None): + super().__init__(game, from_player, from_character) + self.experimentalprogress = 0 + + def excute(self, game): + if self.experimentalprogress > 0: + if self.experimentalprogress % 3 == 0: + self.from_player.dice_zone.add([DiceType.OMNI.value]) + if self.experimentalprogress == self.max_usage: + self.on_destroy(game) + + def on_tune_card(self, game: 'GeniusGame'): + if game.active_player_index == self.from_player.index: + self.experimentalprogress += 1 + self.excute(game) + + def on_discard_card(self, game: 'GeniusGame'): + if game.active_player_index == self.from_player.index: + self.experimentalprogress += 1 + self.excute(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.ON_TUNE_CARD, ZoneType.SUPPORT_ZONE, self.on_tune_card), + (EventType.ON_DISCARD_CARD, ZoneType.SUPPORT_ZONE, self.on_discard_card), + ] + def show(self): + return str(self.usage) + +class CentralLaboratoryRuins(SupportCard): + id: int = 321017 + name = 'Central Laboratory Ruins' + name_ch = '中央实验室遗址' + cost_num = 1 + cost_type = CostType.WHITE + card_type = ActionCardType.SUPPORT_LOCATION + + def __init__(self) -> None: + super().__init__() + self.entity = None + + def on_played(self, game: 'GeniusGame') -> None: + self.entity = CentralLaboratoryRuinsEntity(game, from_player=game.active_player) + super().on_played(game) \ No newline at end of file diff --git a/genius_invocation/card/action/support/location/Fortress_of_Meropide.py b/genius_invocation/card/action/support/location/Fortress_of_Meropide.py index b7f5bccf..c03a9fdf 100644 --- a/genius_invocation/card/action/support/location/Fortress_of_Meropide.py +++ b/genius_invocation/card/action/support/location/Fortress_of_Meropide.py @@ -36,7 +36,7 @@ def update_listener_list(self): ] class Fortress_of_Meropide_Entity(Support): id: int = 322018 - name = 'Fortress_of_Meropide' + name = 'Fortress of Meropide' name_ch = '梅洛彼得堡' max_usage = -1 max_count = 4 @@ -73,7 +73,7 @@ def show(self): class Fortress_of_Meropide(SupportCard): id: int = 321018 - name: str = 'Fortress_of_Meropide' + name: str = 'Fortress of Meropide' name_ch = '梅洛彼得堡' cost_num = 1 cost_type = CostType.WHITE diff --git a/genius_invocation/card/action/support/location/TheMausoleumofKingDeshret.py b/genius_invocation/card/action/support/location/TheMausoleumofKingDeshret.py new file mode 100644 index 00000000..976585b5 --- /dev/null +++ b/genius_invocation/card/action/support/location/TheMausoleumofKingDeshret.py @@ -0,0 +1,122 @@ +from genius_invocation.utils import * +from genius_invocation.card.action.support.base import SupportCard +from typing import TYPE_CHECKING +from genius_invocation.entity.support import Support +from genius_invocation.entity.status import Combat_Status +from genius_invocation.event.damage import Damage + + +if TYPE_CHECKING: + from genius_invocation.game.game import GeniusGame + from genius_invocation.game.player import GeniusPlayer + + +class HasForbiddenKnowledge(Combat_Status): + name: str = 'Forbidden Knowledge' + name_ch = '禁忌知识' + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character=None): + super().__init__(game, from_player, from_character) + + def on_end(self, game:'GeniusGame'): + self.on_destroy(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.FINAL_END, ZoneType.ACTIVE_ZONE, self.on_end), + ] + +class ForbiddenKnowledge(ActionCard): + name = "Forbidden Knowledge" + name_ch = "禁忌知识" + cost_num = 0 + cost_type = None + card_type = ActionCardType.EVENT + can_tune = False + def __init__(self) -> None: + super().__init__() + + def on_played(self, game: 'GeniusGame') -> None: + dmg = Damage.create_damage( + game, + damage_type=SkillType.OTHER, + main_damage_element=ElementType.PIERCING, + main_damage=1, + piercing_damage=0, + damage_from=None, + damage_to=get_my_active_character(game), + ) + game.add_damage(dmg) + game.resolve_damage() + game.active_player.get_card(num=1) + + def on_tuning(self, game: 'GeniusGame') -> None: + pass + + def find_target(self, game: 'GeniusGame'): + if game.active_player.last_die_round == game.round : + if game.active_player.team_combat_status.has_status(HasForbiddenKnowledge) is None: + return [1] + return [] + + +class TheMausoleumofKingDeshretStatus(Combat_Status): + name: str = 'The Mausoleum of King Deshret' + name_ch = '赤王陵' + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character=None): + super().__init__(game, from_player, from_character) + + def on_get_card(self, game: 'GeniusGame'): + if game.current_get_card.from_player == self.from_player: + self.from_player.card_zone.place_randomly([ForbiddenKnowledge()]) + + def on_end(self, game:'GeniusGame'): + self.on_destroy(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.ON_PLAY_CARD, ZoneType.ACTIVE_ZONE, self.on_play), + (EventType.FINAL_END, ZoneType.ACTIVE_ZONE, self.on_end), + ] + + +class TheMausoleumofKingDeshretEntity(Support): + name: str = 'The Mausoleum of King Deshret' + name_ch = '赤王陵' + max_count = 4 + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character=None): + super().__init__(game, from_player, from_character) + self.count = 0 + self.oppenent = get_opponent(game) + + def on_get_card(self, game: 'GeniusGame'): + if game.current_get_card.from_player == self.oppenent: + self.count += 1 + if self.count == self.max_count: + self.on_destroy(game) + for _ in range(2): + self.oppenent.card_zone.insert_randomly(ForbiddenKnowledge(), 0) + self.oppenent.team_combat_status.add_entity(TheMausoleumofKingDeshretStatus(game, self.oppenent)) + + def update_listener_list(self): + self.listeners = [ + (EventType.ON_GET_CARD, ZoneType.SUPPORT_ZONE, self.on_get_card), + ] + + def show(self): + return str(self.count) + +class TheMausoleumofKingDeshret(SupportCard): + id: int = 321018 + name: str = 'The Mausoleum of King Deshret' + name_ch = '赤王陵' + cost_num = 1 + cost_type = CostType.WHITE + card_type = ActionCardType.SUPPORT_LOCATION + + def __init__(self) -> None: + super().__init__() + self.entity = None + + def on_played(self, game: 'GeniusGame') -> None: + self.entity = TheMausoleumofKingDeshretEntity(game, from_player=game.active_player) + super().on_played(game) \ No newline at end of file diff --git a/genius_invocation/game/game.py b/genius_invocation/game/game.py index 9702ca27..f2b18abd 100644 --- a/genius_invocation/game/game.py +++ b/genius_invocation/game/game.py @@ -8,7 +8,7 @@ from genius_invocation.event.events import EventManager from genius_invocation.card.character.base import Damage from genius_invocation.card.action.base import ActionCard -from genius_invocation.game.zone import Dice +from genius_invocation.game.zone import Dice, GetCard from genius_invocation.event.heal import Heal from loguru import logger from rich.console import Console @@ -59,6 +59,7 @@ def __init__(self, player0_deck, player1_deck, seed=None, is_omni=False) -> None self.current_skill: CharacterSkill = None self.current_card: ActionCard = None self.current_remove_from: Character = None + self.current_get_card: GetCard = None self.damage_list: List[Damage] = [] self.is_change_player: bool = False self.current_attach_reaction: ElementalReactionType = None # Save the reaction type when attachment (no dmg). Will be reset after the invoking of the event. keep None. @@ -66,7 +67,6 @@ def __init__(self, player0_deck, player1_deck, seed=None, is_omni=False) -> None self.is_end: bool = False self.is_overload:GeniusPlayer = None self.can_play_card = True - self.get_card_num = 0 self.init_game() diff --git a/genius_invocation/game/player.py b/genius_invocation/game/player.py index 366f23a2..d62d1e66 100644 --- a/genius_invocation/game/player.py +++ b/genius_invocation/game/player.py @@ -56,6 +56,9 @@ def __init__(self, game: 'GeniusGame', deck, idx) -> None: self.is_pass: bool self.play_arcane_legend: bool = False + # 回合打出手牌数量 + self.round_play_cards = 0 + # 切换角色基本信息 self.is_after_change: bool self.is_quick_change: bool @@ -131,9 +134,7 @@ def get_card(self, num): ''' get_cards = self.card_zone.get_card(num=num) self.hand_zone.add(get_cards) - self.game.get_card_num = num - self.game.manager.invoke(EventType.ON_GET_CARD, self.game) - self.game.get_card_num = 0 + def change_to_id(self, idx: int): ''' @@ -315,7 +316,7 @@ def generate_mask(self, game: 'GeniusGame'): from_character=None, use_type=SwitchType.ELEMENTAL_RESONANCE, cost = [{'cost_num':1, 'cost_type':active_dice}])) - if can_tune: + if can_tune and action_card.can_tune: self.action_mask[idx][13][0] = 1 self.action_mask[idx][13][1] = 1 self.action_mask[idx][13][2] = - (active_dice.value) @@ -388,6 +389,7 @@ def begin_action_phase(self, game: 'GeniusGame'): self.is_after_change = False self.is_quick_change = False self.change_num = 0 + self.round_play_cards = 0 # 事件 game.manager.invoke(EventType.BEGIN_ACTION_PHASE, game) @@ -398,7 +400,7 @@ def end_phase(self, game: 'GeniusGame'): ''' # 事件 game.manager.invoke(EventType.END_PHASE, game) - self.roll_time = 2 + # self.roll_time = 2 self.get_card(num=2) diff --git a/genius_invocation/game/zone.py b/genius_invocation/game/zone.py index 9b7b92c2..03363752 100644 --- a/genius_invocation/game/zone.py +++ b/genius_invocation/game/zone.py @@ -16,6 +16,13 @@ from genius_invocation.entity.character import Character +class GetCard: + ''' + 获取牌的维护类 + ''' + def __init__(self, from_player, num) -> None: + self.from_player = from_player + self.num = num class Dice: ''' @@ -239,8 +246,17 @@ def __init__(self, game: 'GeniusGame', player: 'GeniusPlayer', card: List) -> No self.card_num = len(self.card) # 随机固定牌序 self.game = game + self.player = player game.random.shuffle(self.card) + def invoke_get_card(self, num): + ''' + 触发获取牌事件 + ''' + self.game.current_get_card = GetCard(from_player=self.player, num=num) + self.game.manager.invoke(EventType.ON_GET_CARD, self.game) + self.game.current_get_card = None + def find_card(self, card_type: 'ActionCardType', num=1): ''' 检索并获取特定类型的牌 @@ -256,8 +272,10 @@ def find_card(self, card_type: 'ActionCardType', num=1): break for idx in idx_list: self.card.pop(idx) + + self.invoke_get_card(num) return get_list - + def random_find_card(self, card_type: 'ActionCardType', num=1): ''' 随机检索并获取特定类型的牌 @@ -270,6 +288,8 @@ def random_find_card(self, card_type: 'ActionCardType', num=1): get_idx = random.sample(idx_list, num) for idx in get_idx: get_list.append(self.card.pop(idx)) + + self.invoke_get_card(num) return get_list def get_card(self, num): @@ -280,6 +300,8 @@ def get_card(self, num): for i in range(num): get_list.append(self.card.pop()) self.card_num = len(self.card) + + self.invoke_get_card(num) return get_list def return_card(self, card_list: List): @@ -303,13 +325,13 @@ def place_randomly(self, card_list: List): ''' 将牌随机放回牌堆 ''' - result = evenly_insert(self.card, card_list) + result = random_insert(self.card, card_list) self.card = result self.card_num = len(self.card) def insert_randomly(self, card, num=-1): ''' - 从牌堆顶随机插入单张牌 + 从牌堆顶的指定数量牌中随机插入单张牌 ''' num = self.card_num if num == -1 else num idx = random.randint(0, num) @@ -566,5 +588,6 @@ def discard_card(self, idx): ''' 舍弃牌 ''' - pass + card: ActionCard = self.pop(idx) + card.on_discard(self.game) self.game.invoke(EventType.ON_DISCARD_CARD, self.game) diff --git a/uncompleted.txt b/uncompleted.txt index e13d9c5e..43052ac3 100644 --- a/uncompleted.txt +++ b/uncompleted.txt @@ -2,11 +2,7 @@ # 平衡性调整 # 装备 # 事件 - -赤王陵 -中央实验室遗址 -亚瑟先生 -苦舍桓 +# 支援 云堇 卡维