diff --git a/genius_invocation/card/action/base.py b/genius_invocation/card/action/base.py index 17c4df6a..5e8c73a7 100644 --- a/genius_invocation/card/action/base.py +++ b/genius_invocation/card/action/base.py @@ -16,6 +16,9 @@ class ActionCard: card_type: ActionCardType can_tune: bool = True + def __init__(self) -> None: + self.zone = None + def calculate_dice(self) -> int: if self.cost_type == ActionCardType.EQUIPMENT_TALENT: count = sum([i['cost_num'] for i in self.cost]) diff --git a/genius_invocation/card/action/equipment/artifact/artifacts/GladiatorsTriumphus.py b/genius_invocation/card/action/equipment/artifact/artifacts/GladiatorsTriumphus.py new file mode 100644 index 00000000..6a1f8b27 --- /dev/null +++ b/genius_invocation/card/action/equipment/artifact/artifacts/GladiatorsTriumphus.py @@ -0,0 +1,60 @@ +from genius_invocation.utils import * +from genius_invocation.card.action.equipment.artifact.base import ArtifactCard +from genius_invocation.entity.status import Artifact +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from genius_invocation.game.game import GeniusGame + from genius_invocation.game.player import GeniusPlayer + + +class GladiatorsTriumphusEntity(Artifact): + id = 31202991 + name: str = "Gladiator's Triumphus" + name_ch = "角斗士的凯旋" + max_usage = 1 + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character = None, artifact_card = None): + super().__init__(game, from_player, from_character, artifact_card) + self.round_usage = 1 + + def on_calculate(self, game: 'GeniusGame'): + if self.round_usage > 0: + if game.active_player_index == self.from_player.index: + if game.current_dice.from_character == self.from_character: + if game.current_dice.use_type == SkillType.NORMAL_ATTACK: + 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'): + if self.on_calculate(game): + self.round_usage = 0 + + def on_end(self, game: 'GeniusGame'): + self.round_usage = 1 + + def update_listener_list(self): + self.listeners = [ + (EventType.ON_USE_SKILL, ZoneType.CHARACTER_ZONE, self.on_skill), + (EventType.CALCULATE_DICE, ZoneType.CHARACTER_ZONE, self.on_calculate), + (EventType.FINAL_END, ZoneType.CHARACTER_ZONE, self.on_end) + ] + + + +class GladiatorsTriumphus(ArtifactCard): + id: int = 312029 + name: str = "Gladiator's Triumphus" + name_ch = "角斗士的凯旋" + time = 4.8 + cost_num: int = 0 + cost_type: CostType = None + + def __init__(self) -> None: + super().__init__() + self.artifact_entity = GladiatorsTriumphusEntity + + def on_played(self, game: 'GeniusGame') -> None: + super().on_played(game) + diff --git a/genius_invocation/card/action/equipment/talent/base.py b/genius_invocation/card/action/equipment/talent/base.py index 5e1bb761..37c6398a 100644 --- a/genius_invocation/card/action/equipment/talent/base.py +++ b/genius_invocation/card/action/equipment/talent/base.py @@ -22,7 +22,7 @@ def __init__(self) -> None: super().__init__() for i in range(len(self.cost)): self.cost[i]['cost_type'] = CostType(self.cost[i]['cost_type']) - + def on_played(self, game: 'GeniusGame') -> None: target_character = game.active_player.character_list[game.current_action.target_idx] target_character.equip_talent(game, self.is_action, self) @@ -31,13 +31,14 @@ def find_target(self, game: 'GeniusGame'): if not self.is_action: for idx, character in enumerate(game.active_player.character_list): if isinstance(character, self.character): - return [idx+2] + if character.is_alive: + return [idx+2] else: if isinstance(get_my_active_character(game), self.character): if get_my_active_character(game).power >= self.cost_power: return [game.active_player.active_idx+2] return [] - + def count_cost(self): if self.is_equip: return sum([cost['cost_num'] for cost in self.cost]) diff --git a/genius_invocation/card/action/equipment/talent/talents/RimeflowRapier.py b/genius_invocation/card/action/equipment/talent/talents/RimeflowRapier.py new file mode 100644 index 00000000..95f636a0 --- /dev/null +++ b/genius_invocation/card/action/equipment/talent/talents/RimeflowRapier.py @@ -0,0 +1,14 @@ +from genius_invocation.card.action.equipment.talent.import_head import * +from genius_invocation.card.character.characters.Navia import * + +class RimeflowRapier(TalentCard): + id: int = 221041 + name: str = "Rimeflow Rapier" + name_ch = "冰雅刺剑" + time = 4.8 + is_action = True + cost = [{'cost_num': 3, 'cost_type': CostType.GEO.value}] + cost_power = 0 + character = Navia + def __init__(self) -> None: + super().__init__() diff --git a/genius_invocation/card/action/equipment/talent/talents/UndisclosedDistributionChannels.py b/genius_invocation/card/action/equipment/talent/talents/UndisclosedDistributionChannels.py new file mode 100644 index 00000000..43763405 --- /dev/null +++ b/genius_invocation/card/action/equipment/talent/talents/UndisclosedDistributionChannels.py @@ -0,0 +1,14 @@ +from genius_invocation.card.action.equipment.talent.import_head import * +from genius_invocation.card.character.characters.FrostOperative import * + +class UndisclosedDistributionChannels(TalentCard): + id: int = 216081 + name: str = "Undisclosed Distribution Channels" + name_ch = "不明流通渠道" + time = 4.8 + is_action = True + cost = [{'cost_num': 3, 'cost_type': CostType.CRYO.value}] + cost_power = 0 + character = FrostOperative + def __init__(self) -> None: + super().__init__() diff --git a/genius_invocation/card/action/equipment/talent/talents/VanguardsCoordinatedTactics.py b/genius_invocation/card/action/equipment/talent/talents/VanguardsCoordinatedTactics.py new file mode 100644 index 00000000..7f5f26a9 --- /dev/null +++ b/genius_invocation/card/action/equipment/talent/talents/VanguardsCoordinatedTactics.py @@ -0,0 +1,23 @@ +from genius_invocation.card.action.equipment.talent.import_head import * +from genius_invocation.card.character.characters.Chevreuse import * + +class VanguardsCoordinatedTactics(TalentCard): + id: int = 213131 + name: str = "Vanguard's Coordinated Tactics" + name_ch = "尖兵协同战法" + time = 4.8 + is_action = False + cost = [{'cost_num': 2, 'cost_type': CostType.PYRO.value}] + cost_power = 0 + character = Chevreuse + def __init__(self) -> None: + super().__init__() + + def find_target(self, game: 'GeniusGame'): + for idx, character in enumerate(game.active_player.character_list): + if isinstance(character, self.character): + if character.is_alive: + unique_element_set = character.from_player.element_set + if len(unique_element_set) == 2 and ElementType.PYRO in unique_element_set and ElementType.ELECTRO in unique_element_set: + return [idx+2] + return [] diff --git a/genius_invocation/card/action/equipment/weapon/weapons/MagicSword.py b/genius_invocation/card/action/equipment/weapon/weapons/MagicSword.py new file mode 100644 index 00000000..19b8f8cc --- /dev/null +++ b/genius_invocation/card/action/equipment/weapon/weapons/MagicSword.py @@ -0,0 +1,56 @@ +from genius_invocation.utils import * +from genius_invocation.card.action.equipment.weapon.base import WeaponCard +from typing import TYPE_CHECKING +from genius_invocation.entity.status import Weapon + +if TYPE_CHECKING: + from genius_invocation.game.game import GeniusGame + + +class MagicSwordWeapon(Weapon): + id: int = 31130881 + name: str = "Ultimate Overlord's Mega Magic Sword" + name_ch = "「究极霸王超级魔剑」" + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character = None, weapon_card = None): + super().__init__(game, from_player, from_character, weapon_card) + self.support = 0 + for card_name in from_player.played_cards: + if card_name not in self.from_player.card_zone.card_name: + self.support += 1 + + def on_add_damage(self, game:'GeniusGame'): + if game.current_damage.damage_from == self.from_character: + if self.support >= 8: + game.current_damage.damage += 3 + elif self.support >= 4: + game.current_damage.damage += 2 + elif self.support >= 2: + game.current_damage.damage += 1 + + def on_play_card(self, game:'GeniusGame'): + if game.active_player_index == self.from_player.index: + if game.current_card.name not in self.from_player.card_zone.card_name: + self.support += 1 + + def update_listener_list(self): + self.listeners = [ + (EventType.DAMAGE_ADD, ZoneType.CHARACTER_ZONE, self.on_add_damage), + (EventType.AFTER_PLAY_CARD, ZoneType.CHARACTER_ZONE, self.on_play_card), + ] + + +class MagicSword(WeaponCard): + id: int = 311308 + name: str = "Ultimate Overlord's Mega Magic Sword" + name_ch = "「究极霸王超级魔剑」" + time = 4.8 + weapon_type: WeaponType = WeaponType.CLAYMORE + cost_num: int = 2 + cost_type: CostType = CostType.WHITE + + def __init__(self) -> None: + super().__init__() + self.equipment_entity = MagicSwordWeapon + + def on_played(self, game: 'GeniusGame') -> None: + super().on_played(game) diff --git a/genius_invocation/card/action/equipment/weapon/weapons/ProspectorsDrill.py b/genius_invocation/card/action/equipment/weapon/weapons/ProspectorsDrill.py new file mode 100644 index 00000000..668e4d1b --- /dev/null +++ b/genius_invocation/card/action/equipment/weapon/weapons/ProspectorsDrill.py @@ -0,0 +1,73 @@ +from genius_invocation.utils import * +from genius_invocation.card.action.equipment.weapon.base import WeaponCard +from typing import TYPE_CHECKING +from genius_invocation.entity.status import Weapon + +if TYPE_CHECKING: + from genius_invocation.game.game import GeniusGame + + +class ProspectorsDrillWeapon(Weapon): + id: int = 31140981 + name: str = "Prospector's Drill" + name_ch = "勘探钻机" + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character = None, weapon_card = None): + super().__init__(game, from_player, from_character, weapon_card) + self.round_usage = 2 + self.solidarity = 0 + self.add_damage = False + + def on_damage_execute(self, game: 'GeniusGame'): + if self.round_usage <=0 : + return + if game.current_damage.damage_to == self.from_character: + if game.current_damage.main_damage_element == ElementType.PIERCING: + return + if game.current_damage.main_damage > 0: + max_id = max_count_card() + if max_id == None: + return + else: + game.current_damage.main_damage -= 1 + self.round_usage -= 1 + + def on_add_damage(self, game:'GeniusGame'): + if self.add_damage: + game.current_damage.main_damage += 1 + self.add_damage = False + + def after_use_skill(self, game: 'GeniusGame'): + if self.add_damage: + self.add_damage = False + + def on_use_skill(self, game: 'GeniusGame'): + if game.current_skill.from_character == self.from_character: + if self.solidarity > 0: + self.add_damage = True + self.from_player.get_card(num=self.solidarity) + self.solidarity = 0 + + def update_listener_list(self): + self.listeners = [ + (EventType.FINAL_EXECUTE, ZoneType.CHARACTER_ZONE, self.on_damage_execute), + (EventType.DAMAGE_ADD, ZoneType.CHARACTER_ZONE, self.on_add_damage), + (EventType.AFTER_USE_SKILL, ZoneType.CHARACTER_ZONE, self.after_use_skill), + (EventType.ON_USE_SKILL, ZoneType.CHARACTER_ZONE, self.on_use_skill) + ] + + +class ProspectorsDrill(WeaponCard): + id: int = 311409 + name: str = "Prospector's Drill" + name_ch = "勘探钻机" + time = 4.8 + weapon_type: WeaponType = WeaponType.POLEARM + cost_num: int = 2 + cost_type: CostType = CostType.WHITE + + def __init__(self) -> None: + super().__init__() + self.equipment_entity = ProspectorsDrillWeapon + + def on_played(self, game: 'GeniusGame') -> None: + super().on_played(game) diff --git a/genius_invocation/card/action/event/__init__.py b/genius_invocation/card/action/event/__init__.py index 1737d1a9..a937aa9e 100644 --- a/genius_invocation/card/action/event/__init__.py +++ b/genius_invocation/card/action/event/__init__.py @@ -1,5 +1,7 @@ from .events import * from .base import FoodCard from .foods import * -from .elemental_resonance import * +from .elemental_resonance_dice import * +from .elemental_resonance_event import * +from .country_resonance import * from .arcane_legend import* \ No newline at end of file diff --git a/genius_invocation/card/action/event/events/Nature_and_Wisdom.py b/genius_invocation/card/action/event/country_resonance/Nature_and_Wisdom.py similarity index 100% rename from genius_invocation/card/action/event/events/Nature_and_Wisdom.py rename to genius_invocation/card/action/event/country_resonance/Nature_and_Wisdom.py diff --git a/genius_invocation/card/action/event/events/Stone_and_Contracts.py b/genius_invocation/card/action/event/country_resonance/Stone_and_Contracts.py similarity index 100% rename from genius_invocation/card/action/event/events/Stone_and_Contracts.py rename to genius_invocation/card/action/event/country_resonance/Stone_and_Contracts.py diff --git a/genius_invocation/card/action/event/events/Thunder_and_Eternity.py b/genius_invocation/card/action/event/country_resonance/Thunder_and_Eternity.py similarity index 100% rename from genius_invocation/card/action/event/events/Thunder_and_Eternity.py rename to genius_invocation/card/action/event/country_resonance/Thunder_and_Eternity.py diff --git a/genius_invocation/card/action/event/events/WaterandJustice.py b/genius_invocation/card/action/event/country_resonance/WaterandJustice.py similarity index 97% rename from genius_invocation/card/action/event/events/WaterandJustice.py rename to genius_invocation/card/action/event/country_resonance/WaterandJustice.py index 3e7a0571..24ee050e 100644 --- a/genius_invocation/card/action/event/events/WaterandJustice.py +++ b/genius_invocation/card/action/event/country_resonance/WaterandJustice.py @@ -47,7 +47,7 @@ def on_played(self, game: 'GeniusGame'): # 进行对应操作 for idx, character in enumerate(character_list): if target_point > character.health_point: - character.heal(heal=target_point[idx]-character.health_point, game=game) + character.heal(heal=target_point[idx]-character.health_point, game=game, heal_type=HealType.HEALTH_ASSIGNMENT) elif target_point < character.health_point: damage = Damage.create_damage( game=game, diff --git a/genius_invocation/card/action/event/events/Wind_and_Freedom.py b/genius_invocation/card/action/event/country_resonance/Wind_and_Freedom.py similarity index 100% rename from genius_invocation/card/action/event/events/Wind_and_Freedom.py rename to genius_invocation/card/action/event/country_resonance/Wind_and_Freedom.py diff --git a/genius_invocation/card/action/event/elemental_resonance/__init__.py b/genius_invocation/card/action/event/country_resonance/__init__.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/__init__.py rename to genius_invocation/card/action/event/country_resonance/__init__.py diff --git a/genius_invocation/card/action/event/elemental_resonance/Woven_Flames.py b/genius_invocation/card/action/event/elemental_resonance_dice/Woven_Flames.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/Woven_Flames.py rename to genius_invocation/card/action/event/elemental_resonance_dice/Woven_Flames.py diff --git a/genius_invocation/card/action/event/elemental_resonance/Woven_Ice.py b/genius_invocation/card/action/event/elemental_resonance_dice/Woven_Ice.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/Woven_Ice.py rename to genius_invocation/card/action/event/elemental_resonance_dice/Woven_Ice.py diff --git a/genius_invocation/card/action/event/elemental_resonance/Woven_Stone.py b/genius_invocation/card/action/event/elemental_resonance_dice/Woven_Stone.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/Woven_Stone.py rename to genius_invocation/card/action/event/elemental_resonance_dice/Woven_Stone.py diff --git a/genius_invocation/card/action/event/elemental_resonance/Woven_Thunder.py b/genius_invocation/card/action/event/elemental_resonance_dice/Woven_Thunder.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/Woven_Thunder.py rename to genius_invocation/card/action/event/elemental_resonance_dice/Woven_Thunder.py diff --git a/genius_invocation/card/action/event/elemental_resonance/Woven_Waters.py b/genius_invocation/card/action/event/elemental_resonance_dice/Woven_Waters.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/Woven_Waters.py rename to genius_invocation/card/action/event/elemental_resonance_dice/Woven_Waters.py diff --git a/genius_invocation/card/action/event/elemental_resonance/Woven_Weeds.py b/genius_invocation/card/action/event/elemental_resonance_dice/Woven_Weeds.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/Woven_Weeds.py rename to genius_invocation/card/action/event/elemental_resonance_dice/Woven_Weeds.py diff --git a/genius_invocation/card/action/event/elemental_resonance/Woven_Winds.py b/genius_invocation/card/action/event/elemental_resonance_dice/Woven_Winds.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/Woven_Winds.py rename to genius_invocation/card/action/event/elemental_resonance_dice/Woven_Winds.py diff --git a/genius_invocation/card/action/event/elemental_resonance_dice/__init__.py b/genius_invocation/card/action/event/elemental_resonance_dice/__init__.py new file mode 100644 index 00000000..ddecb014 --- /dev/null +++ b/genius_invocation/card/action/event/elemental_resonance_dice/__init__.py @@ -0,0 +1,13 @@ +import os +import importlib + +package_dir = os.path.dirname(__file__) +module_files = [ + f[:-3] for f in os.listdir(package_dir) if f.endswith(".py") and f != "__init__.py" +] + +for module_name in module_files: + import_cmd = f"from .{module_name} import *" + exec(import_cmd) + +__all__ = module_files \ No newline at end of file diff --git a/genius_invocation/card/action/event/elemental_resonance/Enduring_Rock.py b/genius_invocation/card/action/event/elemental_resonance_event/Enduring_Rock.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/Enduring_Rock.py rename to genius_invocation/card/action/event/elemental_resonance_event/Enduring_Rock.py diff --git a/genius_invocation/card/action/event/elemental_resonance/Fervent_Flames.py b/genius_invocation/card/action/event/elemental_resonance_event/Fervent_Flames.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/Fervent_Flames.py rename to genius_invocation/card/action/event/elemental_resonance_event/Fervent_Flames.py diff --git a/genius_invocation/card/action/event/elemental_resonance/High_Voltage.py b/genius_invocation/card/action/event/elemental_resonance_event/High_Voltage.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/High_Voltage.py rename to genius_invocation/card/action/event/elemental_resonance_event/High_Voltage.py diff --git a/genius_invocation/card/action/event/elemental_resonance/Impetuous_Winds.py b/genius_invocation/card/action/event/elemental_resonance_event/Impetuous_Winds.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/Impetuous_Winds.py rename to genius_invocation/card/action/event/elemental_resonance_event/Impetuous_Winds.py diff --git a/genius_invocation/card/action/event/elemental_resonance/Shattering_Ice.py b/genius_invocation/card/action/event/elemental_resonance_event/Shattering_Ice.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/Shattering_Ice.py rename to genius_invocation/card/action/event/elemental_resonance_event/Shattering_Ice.py diff --git a/genius_invocation/card/action/event/elemental_resonance/Soothing_Water.py b/genius_invocation/card/action/event/elemental_resonance_event/Soothing_Water.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/Soothing_Water.py rename to genius_invocation/card/action/event/elemental_resonance_event/Soothing_Water.py diff --git a/genius_invocation/card/action/event/elemental_resonance/Sprawling_Greenery.py b/genius_invocation/card/action/event/elemental_resonance_event/Sprawling_Greenery.py similarity index 100% rename from genius_invocation/card/action/event/elemental_resonance/Sprawling_Greenery.py rename to genius_invocation/card/action/event/elemental_resonance_event/Sprawling_Greenery.py diff --git a/genius_invocation/card/action/event/elemental_resonance_event/__init__.py b/genius_invocation/card/action/event/elemental_resonance_event/__init__.py new file mode 100644 index 00000000..ddecb014 --- /dev/null +++ b/genius_invocation/card/action/event/elemental_resonance_event/__init__.py @@ -0,0 +1,13 @@ +import os +import importlib + +package_dir = os.path.dirname(__file__) +module_files = [ + f[:-3] for f in os.listdir(package_dir) if f.endswith(".py") and f != "__init__.py" +] + +for module_name in module_files: + import_cmd = f"from .{module_name} import *" + exec(import_cmd) + +__all__ = module_files \ No newline at end of file diff --git a/genius_invocation/card/action/event/events/Falls_and_Fortune.py b/genius_invocation/card/action/event/events/Falls_and_Fortune.py index 383f7535..6ece68f2 100644 --- a/genius_invocation/card/action/event/events/Falls_and_Fortune.py +++ b/genius_invocation/card/action/event/events/Falls_and_Fortune.py @@ -19,10 +19,14 @@ def on_calculate(self, game:'GeniusGame'): def on_change(self, game:'GeniusGame'): self.on_calculate(game) + def on_end(self, game:'GeniusGame'): + self.on_destroy(game) + def update_listener_list(self): self.listeners = [ (EventType.CALCULATE_DICE, ZoneType.ACTIVE_ZONE, self.on_calculate), - (EventType.ON_CHANGE_CHARACTER, ZoneType.ACTIVE_ZONE, self.on_change) + (EventType.ON_CHANGE_CHARACTER, ZoneType.ACTIVE_ZONE, self.on_change), + (EventType.FINAL_END, ZoneType.ACTIVE_ZONE, self.on_end), ] class Falls_and_Fortune(ActionCard): diff --git a/genius_invocation/card/action/event/events/LoseMoney.py b/genius_invocation/card/action/event/events/LoseMoney.py new file mode 100644 index 00000000..d5fdd2e4 --- /dev/null +++ b/genius_invocation/card/action/event/events/LoseMoney.py @@ -0,0 +1,48 @@ +from genius_invocation.card.action.base import ActionCard +from genius_invocation.utils import * +from genius_invocation.entity.status import Combat_Status +if TYPE_CHECKING: + from genius_invocation.game.game import GeniusGame + +class LoseMoneyEntity(Combat_Status): + id = 33203631 + name: str = "I'd Rather Lose Money Myself..." + name_ch = '「看到那小子挣钱…」' + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character=None): + super().__init__(game, from_player, from_character) + self.current_usage = 1 + + def on_get_dice(self, game:'GeniusGame'): + if game.current_player.index == 1 - self.from_player.index: + self.current_usage += 1 + if self.current_usage == 2: + self.from_player.dice_zone.add([DiceType.OMNI.value]) + + def on_end(self, game:'GeniusGame'): + self.on_destroy(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.ON_GET_DICE, ZoneType.ACTIVE_ZONE, self.on_get_dice), + (EventType.FINAL_END, ZoneType.ACTIVE_ZONE, self.on_end) + ] + +class LoseMoney(ActionCard): + id: int = 332036 + name: str = "I'd Rather Lose Money Myself..." + name_ch = '「看到那小子挣钱…」' + time = 4.8 + cost_num = 0 + cost_type = None + card_type = ActionCardType.EVENT + + def __init__(self) -> None: + super().__init__() + + def on_played(self, game: 'GeniusGame'): + zone = game.active_player.team_combat_status + if not zone.has_status(LoseMoneyEntity): + zone.add_entity(LoseMoneyEntity(game, game.active_player, None)) + + def find_target(self, game:'GeniusGame'): + return [1] \ No newline at end of file diff --git a/genius_invocation/card/action/event/events/Pankration.py b/genius_invocation/card/action/event/events/Pankration.py index 2d968f69..73e13c48 100644 --- a/genius_invocation/card/action/event/events/Pankration.py +++ b/genius_invocation/card/action/event/events/Pankration.py @@ -16,9 +16,13 @@ def on_after_any(self, game:'GeniusGame'): self.from_player.get_card(num=2) self.on_destroy(game) + def on_end(self, game:'GeniusGame'): + self.on_destroy(game) + def update_listener_list(self): self.listeners = [ (EventType.AFTER_ANY_ACTION, ZoneType.ACTIVE_ZONE, self.on_after_any), + (EventType.FINAL_END, ZoneType.ACTIVE_ZONE, self.on_end), ] class Pankration(ActionCard): diff --git a/genius_invocation/card/action/event/events/Tada.py b/genius_invocation/card/action/event/events/Tada.py new file mode 100644 index 00000000..2c62b438 --- /dev/null +++ b/genius_invocation/card/action/event/events/Tada.py @@ -0,0 +1,54 @@ +from genius_invocation.card.action.base import ActionCard +from genius_invocation.utils import * +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 + +class TadaEntity(Combat_Status): + id = 33203731 + name: str = "Tada!" + 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.from_player.get_card(num=1) + self.on_destroy(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.END_PHASE, ZoneType.ACTIVE_ZONE, self.on_end) + ] + +class LoseMoney(ActionCard): + id = 332037 + name: str = "Tada!" + name_ch = '噔噔!' + time = 4.8 + cost_num = 0 + cost_type = None + card_type = ActionCardType.EVENT + + def __init__(self) -> None: + super().__init__() + + def on_played(self, game: 'GeniusGame'): + dmg = Damage.create_damage( + game, + damage_type=SkillType.OTHER, + main_damage_element=ElementType.PHYSICAL, + main_damage=1, + piercing_damage=0, + damage_from=self.zone, + damage_to=get_active_character(game, 1-self.zone.from_player.index), + ) + game.add_damage(dmg) + game.resolve_damage() + + zone = game.active_player.team_combat_status + if not zone.has_status(TadaEntity): + zone.add_entity(TadaEntity(game, game.active_player, None)) + + def find_target(self, game:'GeniusGame'): + return [1] \ No newline at end of file diff --git a/genius_invocation/card/action/event/foods/Teyvat_Fried_Egg.py b/genius_invocation/card/action/event/foods/Teyvat_Fried_Egg.py index 957c8d9b..c30f62af 100644 --- a/genius_invocation/card/action/event/foods/Teyvat_Fried_Egg.py +++ b/genius_invocation/card/action/event/foods/Teyvat_Fried_Egg.py @@ -39,6 +39,7 @@ def on_played(self, game: 'GeniusGame'): target = game.current_action.target_idx target_character = game.active_player.character_list[target] target_character.revive(game) + target_character.heal(1, game=game) Satisfy_Statue(game, from_player=game.active_player, from_character=target_character) target_character.character_zone.add_entity(Satisfy_Statue) diff --git a/genius_invocation/card/action/support/companion/Serene.py b/genius_invocation/card/action/support/companion/Serene.py new file mode 100644 index 00000000..f763152e --- /dev/null +++ b/genius_invocation/card/action/support/companion/Serene.py @@ -0,0 +1,353 @@ +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.card.action import ActionCard +from genius_invocation.entity.status import Combat_Status +from genius_invocation.event.damage import Damage +import os +from copy import deepcopy + +if TYPE_CHECKING: + from genius_invocation.game.game import GeniusGame + from genius_invocation.game.player import GeniusPlayer + + +class SerenaEntity(Support): + id: int = 322027 + name: str = 'Serena' + name_ch = '瑟琳' + max_usage = 1 + max_count = -1 + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character=None): + super().__init__(game, from_player, from_character) + self.usage = 3 + self.generate(game) + + def generate(self, game:'GeniusGame'): + pass + + def on_begin(self, game:'GeniusGame'): + if game.active_player_index == self.from_player.index: + self.generate(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.BEGIN_ACTION_PHASE, ZoneType.SUPPORT_ZONE, self.on_begin), + ] + + +class Serena(SupportCard): + id: int = 322027 + name: str = 'Serena' + name_ch = '瑟琳' + time = 4.8 + cost_num = 2 + cost_type = CostType.BLACK + card_type = ActionCardType.SUPPORT_COMPANION + + def __init__(self) -> None: + super().__init__() + self.entity = None + + def on_played(self, game: 'GeniusGame') -> None: + self.entity = SerenaEntity(game, from_player=game.active_player) + super().on_played(game) + +class SerenaSupport(ActionCard): + id: int = 32202770 + name: str = 'Serena' + name_ch = '瑟琳的声援' + time = 4.8 + cost_num = 0 + cost_type = None + card_type = ActionCardType.EVENT + def __init__(self) -> None: + super().__init__() + self.cards = [] + cards_dir = "./card/action/event/foods" + available_name = [f[:-3] for f in os.listdir(cards_dir) if f.endswith(".py") and f != "__init__.py" and f != "import_head.py"] + self.cards.extend(available_name) + + def on_played(self, game: 'GeniusGame') -> None: + cards = [] + for i in range(2): + cards.append(random.choice(self.cards)) + game.active_player.hand_zone.add_card_by_name(cards) + + +class CosanzeanaSupport(ActionCard): + id: int = 32202771 + name: str = 'Cosanzeana' + name_ch = '柯莎的声援' + time = 4.8 + cost_num = 0 + cost_type = None + card_type = ActionCardType.EVENT + def __init__(self) -> None: + super().__init__() + self.cards = [] + cards_dir = "./card/action/equipment/weapon/weapons" + available_name = [f[:-3] for f in os.listdir(cards_dir) if f.endswith(".py") and f != "__init__.py" and f != "import_head.py"] + self.cards.extend(available_name) + + def on_played(self, game: 'GeniusGame') -> None: + cards = [] + for i in range(2): + cards.append(random.choice(self.cards)) + game.active_player.hand_zone.add_card_by_name(cards) + + +class LaumeSupport(ActionCard): + id: int = 32202772 + name: str = 'Laume' + name_ch = '洛梅的声援' + time = 4.8 + cost_num = 0 + cost_type = None + card_type = ActionCardType.EVENT + def __init__(self) -> None: + super().__init__() + self.cards = [] + cards_dir = "./card/action/equipment/artifact/artifacts" + available_name = [f[:-3] for f in os.listdir(cards_dir) if f.endswith(".py") and f != "__init__.py" and f != "import_head.py"] + self.cards.extend(available_name) + + def on_played(self, game: 'GeniusGame') -> None: + cards = [] + for i in range(2): + cards.append(random.choice(self.cards)) + game.active_player.hand_zone.add_card_by_name(cards) + +class VirdaSupport(ActionCard): + id: int = 32202773 + name: str = 'Virda' + name_ch = '薇尔妲的声援' + time = 4.8 + cost_num = 2 + cost_type = CostType.BLACK + card_type = ActionCardType.EVENT + def __init__(self) -> None: + super().__init__() + self.cards = [] + cards_dir = "./card/action/event/arcane_legend" + available_name = [f[:-3] for f in os.listdir(cards_dir) if f.endswith(".py") and f != "__init__.py" and f != "import_head.py"] + self.cards.extend(available_name) + + def on_played(self, game: 'GeniusGame') -> None: + cards = [] + for i in range(2): + cards.append(random.choice(self.cards)) + game.active_player.hand_zone.add_card_by_name(cards) + game.active_player.play_arcane_legend = False + +class SluasiSupport(ActionCard): + id: int = 32202774 + name: str = 'Sluasi' + name_ch = '希露艾的声援' + time = 4.8 + cost_num = 1 + cost_type = CostType.WHITE + card_type = ActionCardType.EVENT + def __init__(self) -> None: + super().__init__() + + def on_played(self, game: 'GeniusGame') -> None: + cards = get_opponent(game).card_zone.card[0:3] + self.from_player.hand_zone.add([deepcopy(card) for card in cards]) + + +class CanotilaSupport(ActionCard): + id: int = 32202775 + name: str = 'Canotila' + name_ch = '夏诺蒂拉的声援' + time = 4.8 + cost_num = 1 + cost_type = CostType.WHITE + card_type = ActionCardType.EVENT + def __init__(self) -> None: + super().__init__() + self.cards = [] + cards_dirs = ["./card/action/event/country_resonance", + "./card/action/event/elemental_resonance_event",] + for cards_dir in cards_dirs: + available_name = [f[:-3] for f in os.listdir(cards_dir) if f.endswith(".py") and f != "__init__.py" and f != "import_head.py"] + self.cards.extend(available_name) + + def on_played(self, game: 'GeniusGame') -> None: + cards = [] + for i in range(2): + cards.append(random.choice(self.cards)) + game.active_player.hand_zone.add_card_by_name(cards) + +class ThironaEntity(Combat_Status): + id: int = 32202736 + name: str = 'Thirona' + name_ch = '希洛娜的声援' + def __init__(self, game:'GeniusGame', from_player: 'GeniusPlayer', from_character=None): + super().__init__(game, from_player, from_character) + self.usage = 3 + self.cards = [] + cards_dirs = ["./card/action/event/country_resonance", + "./card/action/event/elemental_resonance_event",] + for cards_dir in cards_dirs: + available_name = [f[:-3] for f in os.listdir(cards_dir) if f.endswith(".py") and f != "__init__.py" and f != "import_head.py"] + self.cards.extend(available_name) + + def on_end(self, game:'GeniusGame'): + if game.active_player_index == self.from_player.index: + card = random.choice(self.cards) + game.active_player.hand_zone.add_card_by_name(card) + self.usage -= 1 + if self.usage <= 0: + self.on_destroy(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.END_PHASE, ZoneType.ACTIVE_ZONE, self.on_end), + ] + +class ThironaSupport(ActionCard): + id: int = 32202776 + name: str = 'Thirona' + name_ch = '希洛娜的声援' + time = 4.8 + cost_num = 0 + cost_type = None + card_type = ActionCardType.EVENT + def __init__(self) -> None: + super().__init__() + + def on_played(self, game: 'GeniusGame') -> None: + game.active_player.team_combat_status.add_entity(ThironaEntity( + game, + from_player=game.active_player, + from_character=None + )) + +class TopyasEntity(Combat_Status): + id: int = 32202737 + name: str = 'Topyas' + name_ch = '托皮娅的声援' + def __init__(self, game:'GeniusGame', from_player: 'GeniusPlayer', from_character=None): + super().__init__(game, from_player, from_character) + + def after_play_card(self, game:'GeniusGame'): + if game.active_player_index == self.from_player.index: + flag = random.random() + if flag < 0.5: + game.active_player.get_card(num=1) + else: + idx = random.randint(0, game.active_player.hand_zone.num()-1) + game.active_player.hand_zone.discard_card(idx) + + def on_end(self, game:'GeniusGame'): + self.on_destroy(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.END_PHASE, ZoneType.ACTIVE_ZONE, self.on_end), + (EventType.AFTER_PLAY_CARD, ZoneType.ACTIVE_ZONE, self.after_play_card) + ] + +class TopyasSupport(ActionCard): + id: int = 32202777 + name: str = 'Topyas' + name_ch = '托皮娅的声援' + time = 4.8 + cost_num = 0 + cost_type = None + card_type = ActionCardType.EVENT + def __init__(self) -> None: + super().__init__() + + def on_played(self, game: 'GeniusGame') -> None: + game.active_player.get_card(num=2) + for player in game.players: + player.team_combat_status.add_entity(TopyasEntity( + game, + from_player=game.active_player, + from_character=None + )) + +class PucaSupport(ActionCard): + id: int = 32202778 + name: str = 'Puca' + name_ch = '芙佳的声援' + time = 4.8 + cost_num = 0 + cost_type = None + card_type = ActionCardType.EVENT + def __init__(self) -> None: + super().__init__() + cards_dirs = ["./card/action/support/companion", + "./card/action/support/item", + "./card/action/support/location"] + self.cards = [] + for package_dir in cards_dirs: + available_name = [f[:-3] for f in os.listdir(package_dir) if f.endswith(".py") and f != "__init__.py" and f != "import_head.py"] + self.cards.extend(available_name) + + def on_played(self, game: 'GeniusGame') -> None: + for player in game.players: + generate_num = MAX_SUPPORT - player.support_zone.num() + for i in range(generate_num): + card_name = random.choice(self.cards) + player.support_zone.add_card_by_name(card_name) + +class LutineEntity(Combat_Status): + id: int = 32202739 + name: str = 'Lutine' + name_ch = '卢蒂尼的声援' + def __init__(self, game:'GeniusGame', from_player: 'GeniusPlayer', from_character=None): + super().__init__(game, from_player, from_character) + + def after_use_skill(self, game:'GeniusGame'): + if game.active_player_index == self.from_player.index: + flag = random.random() + if flag < 0.5: + get_my_active_character(game).heal(heal=2) + else: + dmg = Damage( + damage_type=SkillType.OTHER, + main_damage=2, + main_damage_element=ElementType.PIERCING, + piercing_damage=0, + damage_from=self, + damage_to=get_my_active_character(game) + ) + game.add_damage(dmg) + game.resolve_damage() + + def on_end(self, game:'GeniusGame'): + self.on_destroy(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.END_PHASE, ZoneType.ACTIVE_ZONE, self.on_end), + (EventType.AFTER_USE_SKILL, ZoneType.ACTIVE_ZONE, self.after_use_skill) + ] + +class LutineSupport(ActionCard): + id: int = 32202779 + name: str = 'Lutine' + name_ch = '卢蒂尼的声援' + time = 4.8 + cost_num = 0 + cost_type = None + card_type = ActionCardType.EVENT + def __init__(self) -> None: + super().__init__() + + def on_played(self, game: 'GeniusGame') -> None: + game.active_player.get_card(num=2) + for player in game.players: + player.team_combat_status.add_entity(LutineEntity( + game, + from_player=game.active_player, + from_character=None + )) + + + + diff --git a/genius_invocation/card/character/characters/AbyssHeraldWickedTorrents.py b/genius_invocation/card/character/characters/AbyssHeraldWickedTorrents.py index 0b06c9bf..78dd6531 100644 --- a/genius_invocation/card/character/characters/AbyssHeraldWickedTorrents.py +++ b/genius_invocation/card/character/characters/AbyssHeraldWickedTorrents.py @@ -194,7 +194,7 @@ def on_character_die(self, game: 'GeniusGame'): if not self.from_character.is_alive: self.from_character.is_alive = True self.from_character.health_point = 0 - self.from_character.heal(4, game) + self.from_character.heal(4, game, heal_type=HealType.REVIVE) self.from_character.revive_event(game) if self.from_character.talent: target_zone = get_opponent(game).team_combat_status diff --git a/genius_invocation/card/character/characters/AbyssLectorFathomlessFlames.py b/genius_invocation/card/character/characters/AbyssLectorFathomlessFlames.py index 6d6b1147..627e0841 100644 --- a/genius_invocation/card/character/characters/AbyssLectorFathomlessFlames.py +++ b/genius_invocation/card/character/characters/AbyssLectorFathomlessFlames.py @@ -108,8 +108,8 @@ def on_character_die(self, game: 'GeniusGame'): if not self.from_character.is_alive: self.from_character.is_alive = True self.from_character.health_point = 0 - self.from_character.heal(3, game) - #TODO: check whether this operation is belongs to heal? + self.from_character.heal(4, game, heal_type=HealType.REVIVE) + self.from_character.revive_event(game) if self.set_talent: shield = Aegis_of_Abyssal_Flame(game, self.from_player, self.from_character) self.from_character.character_zone.add_entity(shield) @@ -166,10 +166,24 @@ def __init__(self, game: 'GeniusGame', zone: 'CharacterZone', from_player: 'Geni if self.talent: self.character_zone.has_entity(Fiery_Rebirth).set_talent = True + def on_dmg_add(self, game: 'GeniusGame'): + if game.current_damage.damage_from == self: + if game.current_damage.main_damage_element == ElementType.HYDRO: + game.current_damage.main_damage += 1 + + def infusion(self, game:'GeniusGame'): + if self.from_character == game.current_damage.damage_from: + if game.current_damage.main_damage_element == ElementType.PHYSICAL: + game.current_damage.main_damage_element = ElementType.HYDRO + + def revive_event(self, game: 'GeniusGame'): + self.listen_event(game, EventType.DAMAGE_ADD, ZoneType.CHARACTER_ZONE, self.on_dmg_add) + self.listen_event(game, EventType.INFUSION, ZoneType.CHARACTER_ZONE, self.infusion) + def equip_talent(self, game:'GeniusGame', is_action=True, talent_card=None): self.talent = True self.character_zone.talent_card = talent_card - + rebirth = self.character_zone.has_entity(Fiery_Rebirth) if rebirth is not None: rebirth.set_talent = True diff --git a/genius_invocation/card/character/characters/AllDevouringNarwhal.py b/genius_invocation/card/character/characters/AllDevouringNarwhal.py index 7a511cbc..4021cb5e 100644 --- a/genius_invocation/card/character/characters/AllDevouringNarwhal.py +++ b/genius_invocation/card/character/characters/AllDevouringNarwhal.py @@ -59,10 +59,11 @@ def on_call(self, game: 'GeniusGame'): self.gain_energy(game) max_idx = max_count_card(self.from_character.from_player.hand_zone.card) - card = self.from_character.from_player.hand_zone.discard_card(max_idx) - if self.from_character.talent and self.from_character.talent_round != game.round: - self.from_character.heal(card.calculate_dice(), game) - self.from_character.talent_round = game.round + if max_idx != None: + card = self.from_character.from_player.hand_zone.discard_card(max_idx) + if self.from_character.talent and self.from_character.talent_round != game.round: + self.from_character.heal(card.calculate_dice(), game) + self.from_character.talent_round = game.round # after skill game.manager.invoke(EventType.AFTER_USE_SKILL, game) @@ -169,7 +170,7 @@ def excute(self, game: 'GeniusGame'): self.from_character.max_health_point += addtional_max_health self.from_character.addtional_max_health += addtional_max_health for i in range(4-len(cost_dict)): - self.from_character.heal(num=1, game=game) + self.from_character.heal(num=1, game=game, heal_type=HealType.MAX_HEALTH) def on_tune(self, game: 'GeniusGame'): if len(self.cards)>0 and len(self.cards) % 3 == 0: diff --git a/genius_invocation/card/character/characters/Chevreuse.py b/genius_invocation/card/character/characters/Chevreuse.py new file mode 100644 index 00000000..9e1bcab3 --- /dev/null +++ b/genius_invocation/card/character/characters/Chevreuse.py @@ -0,0 +1,249 @@ +from genius_invocation.card.character.import_head import * +from genius_invocation.card.action.base import ActionCard + + +class OverchargedBall(ActionCard): + id: int = 131371 + name = "Overcharged Ball" + name_ch = "超量装药弹头" + cost_num = 2 + cost_type = CostType.PYRO + card_type = ActionCardType.EVENT + + def __init__(self) -> None: + super().__init__() + + def on_played(self, game: 'GeniusGame'): + dmg = Damage.create_damage( + game, + damage_type=SkillType.OTHER, + main_damage_element=ElementType.PYRO, + main_damage=1, + piercing_damage=0, + damage_from=self.zone, + damage_to=get_active_character(game, 1-self.zone.from_player.index), + ) + game.add_damage(dmg) + game.resolve_damage() + game.is_change_player = True + + def on_discard(self, game: 'GeniusGame'): + dmg = Damage.create_damage( + game, + damage_type=SkillType.OTHER, + main_damage_element=ElementType.PYRO, + main_damage=1, + piercing_damage=0, + damage_from=self.zone, + damage_to=get_active_character(game, 1-self.zone.from_player.index), + ) + game.add_damage(dmg) + game.resolve_damage() + game.is_change_player = True + +class VerticalForceCoordination(CharacterSkill): + id = 131304 + name = 'Vertical Force Coordination' + name_ch = '纵阵武力统筹' + def on_call(self, game:'GeniusGame'): + self.from_character.from_player.hand_zone.add([OverchargedBall()]) + +class LineBayonetThrustEX(NormalAttack): + id: int = 131301 + type: SkillType = SkillType.NORMAL_ATTACK + name = "Invokers Spear" + name_ch = "线列枪刺·改" + damage_type: SkillType = SkillType.NORMAL_ATTACK + main_damage_element: ElementType = ElementType.PHYSICAL + main_damage: int = 2 + piercing_damage: int = 0 + cost = [{ + 'cost_num': 1, + 'cost_type': CostType.PYRO + }, + { + 'cost_num': 2, + 'cost_type': CostType.BLACK + } + ] + energy_cost: int = 0 + energy_gain: int = 1 + + def __init__(self, from_character: 'Character'): + super().__init__(from_character) + + def on_call(self, game: 'GeniusGame'): + super().on_call(game) + self.resolve_damage(game) + self.gain_energy(game) + game.manager.invoke(EventType.AFTER_USE_SKILL, game) + + +class ShortRangeRapidInterdictionFire(ElementalSkill): + id: int = 131302 + name = "Short-Range Rapid Interdiction Fire" + name_ch = "近迫式急促拦射" + type: SkillType = SkillType.ELEMENTAL_SKILL + damage_type: SkillType = SkillType.ELEMENTAL_SKILL + main_damage_element: ElementType = ElementType.PYRO + main_damage: int = 2 + piercing_damage: int = 0 + cost = [ + { + 'cost_num': 3, + 'cost_type': CostType.PYRO + }, + ] + energy_cost: int = 0 + energy_gain: int = 1 + def __init__(self, from_character: 'Character'): + super().__init__(from_character) + + def on_call(self, game: 'GeniusGame'): + super().on_call(game) + self.resolve_damage(game) + self.gain_energy(game) + card = self.from_character.from_player.hand_zone.has_card(OverchargedBall) + if card is not None: + card.on_dsicard(game) + character = max_dmg_taken(self.from_character.from_player) + character.heal(heal=1, game=game) + game.manager.invoke(EventType.AFTER_USE_SKILL, game) + + +class SecondaryExplosiveShells(Combat_Status): + id = 131331 + name = "Secondary Explosive Shells" + name_ch = "二重毁伤弹" + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character = None): + super().__init__(game, from_player, from_character) + self.usage = 2 + self.current_usage = 2 + + def update(self): + self.current_usage = self.usage + + def on_swith(self, game:'GeniusGame'): + if game.current_switch['from'].from_player == self.from_player: + dmg = Damage.create_damage( + game, + damage_type=SkillType.OTHER, + main_damage_element=ElementType.PYRO, + main_damage=1, + piercing_damage=0, + damage_from=self, + damage_to=get_my_active_character(game), + ) + game.add_damage(dmg) + game.resolve_damage() + self.current_usage -= 1 + if self.current_usage <= 0: + self.on_destroy(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.AFTER_CHANGE_CHARACTER, ZoneType.ACTIVE_ZONE, self.on_swith) + ] + +class RingofBurstingGrenades(ElementalBurst): + id = 131303 + name="Ring of Bursting Grenades" + name_ch = "圆阵掷弹爆轰术" + type: SkillType = SkillType.ELEMENTAL_BURST + + # damage + damage_type: SkillType = SkillType.ELEMENTAL_BURST + main_damage_element: ElementType = ElementType.PYRO + main_damage: int = 2 + piercing_damage: int = 0 + + # cost + cost = [ + { + 'cost_num': 3, + 'cost_type': CostType.PYRO + } + ] + energy_cost: int = 2 + energy_gain: int = 0 + + def __init__(self, from_character: 'Character') -> None: + super().__init__(from_character) + + def on_call(self, game: 'GeniusGame'): + super().on_call(game) + self.consume_energy(game) + self.resolve_damage(game) + target_zone = get_opponent(game).team_combat_status + state = target_zone.has_status(SecondaryExplosiveShells) + if state != None: + state.update() + else: + target_zone.add_entity(SecondaryExplosiveShells(game, from_player=get_opponent(game), from_character=None)) + game.manager.invoke(EventType.AFTER_USE_SKILL, game) + + +class PyroQuill(Combat_Status): + id: int = 131332 + name: str = "Pyro Quill" + name_ch = "火翎" + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character: 'Character'): + super().__init__(game, from_player, from_character) + self.usage = 2 + self.current_usage = 2 + self.last_use_round = -1 + + def update(self): + self.current_usage = self.usage + + def on_dmg_add(self, game: 'GeniusGame'): + if not isinstance(game.current_damage.damage_from, Character): return + if game.current_damage.main_damage_element in [ElementType.PYRO, + ElementType.ELECTRO]: + if game.current_damage.damage_from.from_player == self.from_player: + game.current_damage.main_damage += 1 + if self.from_character.talent and game.current_damage.damage_type==SkillType.NORMAL_ATTACK and self.last_use_round!= game.round: + self.last_use_round = game.round + else: + self.current_usage -= 1 + if self.current_usage <= 0: + self.on_destroy(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.DAMAGE_ADD, ZoneType.ACTIVE_ZONE, self.on_dmg_add) + ] + +class Chevreuse(Character): + id = 1313 + name = "Chevreuse" + name_ch = "夏沃蕾" + time = 4.8 + element = ElementType.PYRO + weapon_type: WeaponType = WeaponType.POLEARM + country: CountryType = CountryType.FONTAINE + + init_health_point: int = 10 + max_health_point: int = 10 + skill_list = [LineBayonetThrustEX, + ShortRangeRapidInterdictionFire, + RingofBurstingGrenades] + max_power: int = 2 + + def init_state(self, game: 'GeniusGame'): + self.listen_event(game, EventType.DAMAGE_ADD_AFTER_REACTION, ZoneType.CHARACTER_ZONE, self.on_reaction) + + def __init__(self, game: 'GeniusGame', zone: 'CharacterZone', from_player: 'GeniusPlayer', index:int, from_character = None, talent = False): + super().__init__(game, zone, from_player, index, from_character) + self.talent = talent + self.power = 0 + self.talent_skill = None + self.passive_skill = VerticalForceCoordination(self) + + def on_reaction(self, game: 'GeniusGame'): + if game.current_damage.damage_to.from_player.index == 1 - self.from_player.index: + if game.current_damage.reaction == ElementalReactionType.Overloaded: + self.passive_skill.on_reaction(game) + if self.talent: + self.from_player.team_combat_status.add_entity(PyroQuill(game, from_player=self.from_player, from_character=self)) + diff --git a/genius_invocation/card/character/characters/CryoHypostasis.py b/genius_invocation/card/character/characters/CryoHypostasis.py index 3b940478..5c7b89f7 100644 --- a/genius_invocation/card/character/characters/CryoHypostasis.py +++ b/genius_invocation/card/character/characters/CryoHypostasis.py @@ -205,7 +205,7 @@ def on_character_die(self, game: 'GeniusGame'): if not self.from_character.is_alive or self.from_character.health_point<=0: self.from_character.is_alive = True self.from_character.health_point = 0 - self.from_character.heal(1, game) + self.from_character.heal(1, game, heal_type=HealType.REVIVE) if self.talent: opponent_player = game.players[1-self.from_player.index] diff --git a/genius_invocation/card/character/characters/ElectroHypostasis.py b/genius_invocation/card/character/characters/ElectroHypostasis.py index 774abb26..20676318 100644 --- a/genius_invocation/card/character/characters/ElectroHypostasis.py +++ b/genius_invocation/card/character/characters/ElectroHypostasis.py @@ -311,7 +311,7 @@ def on_character_die(self, game: 'GeniusGame'): if not self.from_character.is_alive or self.from_character.health_point<=0: self.from_character.is_alive = True self.from_character.health_point = 0 - self.from_character.heal(1, game) + self.from_character.heal(1, game, heal_type=HealType.REVIVE) self.on_destroy(game) def update_listener_list(self): @@ -324,7 +324,7 @@ class TalentOfElectroHypostasis(CharacterSkill): 无向之雷被动技能 ''' def on_call(self, game: 'GeniusGame'): - self.from_character.heal(3,game=game) + self.from_character.heal(3, game=game) if not self.from_character.character_zone.has_entity(ElectroCrystalCore): electro_crystal_core = ElectroCrystalCore(game=game, from_player=self.from_character.from_player, diff --git a/genius_invocation/card/character/characters/FrostOperative.py b/genius_invocation/card/character/characters/FrostOperative.py new file mode 100644 index 00000000..4f2f81c4 --- /dev/null +++ b/genius_invocation/card/character/characters/FrostOperative.py @@ -0,0 +1,175 @@ +from genius_invocation.card.character.import_head import * +from genius_invocation.card.action.base import ActionCard + + +class BloodBondedShadow(CharacterSkill): + id = 210404 + name = 'Blood-Bonded Shadow' + name_ch = '血契掠影' + def on_call(self, game:'GeniusGame', damage:int): + usage = min(5, damage-2) + target_zone = get_opponent_active_character(game).character_zone + target_zone.add_entity(BondofLife(game, get_opponent(game), get_opponent_active_character(game), usgae=usage), + usage=usage) + if self.from_character.talent: + status = get_opponent_active_character(game).character_zone.has_entity(BondofLife) + status.usage *= 2 + +class SwiftPoint(NormalAttack): + id: int = 210401 + type: SkillType = SkillType.NORMAL_ATTACK + name = "Swift Point" + name_ch = "迅捷剑锋" + damage_type: SkillType = SkillType.NORMAL_ATTACK + main_damage_element: ElementType = ElementType.PHYSICAL + main_damage: int = 2 + piercing_damage: int = 0 + cost = [{ + 'cost_num': 1, + 'cost_type': CostType.CRYO + }, + { + 'cost_num': 2, + 'cost_type': CostType.BLACK + } + ] + energy_cost: int = 0 + energy_gain: int = 1 + + def __init__(self, from_character: 'Character'): + super().__init__(from_character) + + def on_call(self, game: 'GeniusGame'): + super().on_call(game) + self.resolve_damage(game) + self.gain_energy(game) + game.manager.invoke(EventType.AFTER_USE_SKILL, game) + +class FrostyInterjection(ElementalSkill): + id: int = 210402 + name = "Frosty Interjection" + name_ch = "霜刃截击" + type: SkillType = SkillType.ELEMENTAL_SKILL + damage_type: SkillType = SkillType.ELEMENTAL_SKILL + main_damage_element: ElementType = ElementType.CRYO + main_damage: int = 3 + piercing_damage: int = 0 + cost = [ + { + 'cost_num': 3, + 'cost_type': CostType.CRYO + }, + ] + energy_cost: int = 0 + energy_gain: int = 1 + def __init__(self, from_character: 'Character'): + super().__init__(from_character) + + def on_call(self, game: 'GeniusGame'): + super().on_call(game) + self.resolve_damage(game) + self.gain_energy(game) + game.manager.invoke(EventType.AFTER_USE_SKILL, game) + +class OnslaughtStance(Status): + id = 210421 + name = "Onslaught Stance" + name_ch = "掠袭之势" + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character: 'Character'): + super().__init__(game, from_player, from_character) + self.current_usage = 2 + + def on_end_phase(self, game: 'GeniusGame'): + if game.active_player == self.from_player: + for character in get_opponent(game).character_list: + if character.is_alive: + if character.character_zone.has_entity(BondofLife) is not None: + dmg = Damage.create_damage( + game, + SkillType.OTHER, + main_damage_element=ElementType.PIERCING, + main_damage=1, + piercing_damage=0, + damage_from=self, + damage_to=get_opponent_active_character(game), + ) + game.add_damage(dmg) + game.resolve_damage() + + def on_end(self, game: 'GeniusGame'): + self.usage -= 1 + if self.usage == 0: + self.on_destroy(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.END_PHASE, ZoneType.CHARACTER_ZONE, self.on_end_phase), + (EventType.FINAL_END, ZoneType.CHARACTER_ZONE, self.on_end), + ] + +class ThornyOnslaught(ElementalBurst): + id = 210403 + name: str = "Thorny Onslaught" + name_ch = "掠袭之刺" + type: SkillType = SkillType.ELEMENTAL_BURST + + # damage + damage_type: SkillType = SkillType.ELEMENTAL_BURST + main_damage_element: ElementType = ElementType.CRYO + main_damage: int = 4 + piercing_damage: int = 0 + + # cost + cost = [ + { + 'cost_num': 3, + 'cost_type': CostType.CRYO + } + ] + energy_cost: int = 2 + energy_gain: int = 0 + + def __init__(self, from_character: 'Character') -> None: + super().__init__(from_character) + + def on_call(self, game: 'GeniusGame'): + super().on_call(game) + self.consume_energy(game) + self.resolve_damage(game) + self.add_status(game, OnslaughtStance) + game.manager.invoke(EventType.AFTER_USE_SKILL, game) + +class FrostOperative(Character): + id = 2104 + name = "Frost Operative" + name_ch = "愚人众·霜役人" + time = 4.8 + element = ElementType.CRYO + weapon_type: WeaponType = WeaponType.OTHER + country: CountryType = CountryType.MONSTER + country_list: List[CountryType] = [CountryType.MONSTER, CountryType.FATUI] + + init_health_point: int = 10 + max_health_point: int = 10 + skill_list = [SwiftPoint, FrostyInterjection, ThornyOnslaught] + max_power: int = 2 + + def init_state(self, game: 'GeniusGame'): + self.listen_event(game, EventType.AFTER_USE_SKILL, ZoneType.CHARACTER_ZONE, self.after_use_skill) + self.listen_event(game, EventType.EXCUTE_DAMAGE, ZoneType.CHARACTER_ZONE, self.on_excute) + + def __init__(self, game: 'GeniusGame', zone: 'CharacterZone', from_player: 'GeniusPlayer', index:int, from_character = None, talent = False): + super().__init__(game, zone, from_player, index, from_character) + self.talent = talent + self.power = 0 + self.talent_skill = self.skills[1] + self.passive_skill = BloodBondedShadow(self) + self.skill_damage = 0 + + def on_excute(self, game: 'GeniusGame'): + if game.current_damage.damage_from == self: + self.skill_damage = game.current_damage.max_main_damage + + def after_use_skill(self, game: 'GeniusGame'): + if game.current_skill.from_character == self: + self.passive_skill(game, self.skill_damage) diff --git a/genius_invocation/card/character/characters/Kaeya.py b/genius_invocation/card/character/characters/Kaeya.py index b172d390..5ae4bed5 100644 --- a/genius_invocation/card/character/characters/Kaeya.py +++ b/genius_invocation/card/character/characters/Kaeya.py @@ -63,7 +63,7 @@ class Frostgnaw(ElementalSkill): def __init__(self, from_character: 'Character'): super().__init__(from_character) self.heal_round = -1 - + def on_call(self, game: 'GeniusGame'): super().on_call(game) # 处理伤害 @@ -118,7 +118,7 @@ def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_charact self.current_usage = self.usage def on_switch(self, game: 'GeniusGame'): - if game.active_player != self.from_player: return + if game.current_switch['from'].from_player != self.from_player: return dmg = Damage.create_damage( game, damage_type=SkillType.OTHER, diff --git a/genius_invocation/card/character/characters/KukiShinobu.py b/genius_invocation/card/character/characters/KukiShinobu.py index fb58407f..155a2f8c 100644 --- a/genius_invocation/card/character/characters/KukiShinobu.py +++ b/genius_invocation/card/character/characters/KukiShinobu.py @@ -140,7 +140,7 @@ def on_character_die(self, game: 'GeniusGame'): if (not self.from_character.is_alive or self.from_character.health_point<=0) and self.talent_round != game.round: self.from_character.is_alive = True self.from_character.health_point = 0 - self.from_character.heal(1, game) + self.from_character.heal(1, game, heal_type=HealType.REVIVE) self.talent_round = game.round def dmg_add(self, game:'GeniusGame'): diff --git a/genius_invocation/card/character/characters/LaSignora.py b/genius_invocation/card/character/characters/LaSignora.py index be112ec3..323e4568 100644 --- a/genius_invocation/card/character/characters/LaSignora.py +++ b/genius_invocation/card/character/characters/LaSignora.py @@ -233,7 +233,7 @@ def on_character_die(self, game: 'GeniusGame'): if not self.from_character.is_alive: self.from_character.is_alive = True self.from_character.health_point = 0 - self.from_character.heal(1, game) + self.from_character.heal(1, game, heal_type=HealType.REVIVE) #TODO: check whether this operation is belongs to heal? self.on_destroy(game) diff --git a/genius_invocation/card/character/characters/Lisa.py b/genius_invocation/card/character/characters/Lisa.py index 54b2e677..68772b6a 100644 --- a/genius_invocation/card/character/characters/Lisa.py +++ b/genius_invocation/card/character/characters/Lisa.py @@ -227,4 +227,9 @@ def __init__(self, game: 'GeniusGame', zone: 'CharacterZone', from_player: 'Geni super().__init__(game, zone, from_player, index, from_character) self.power = 0 self.talent = talent - self.talent_on = 1 \ No newline at end of file + self.talent_on = 1 + + def balance_adjustment(): + log = {} + log[4.8] = "调整了角色牌「丽莎」元素爆发的效果:增加了效果“使敌方出战角色附属引雷”" + return log \ No newline at end of file diff --git a/genius_invocation/card/character/characters/Navia.py b/genius_invocation/card/character/characters/Navia.py new file mode 100644 index 00000000..ff92641a --- /dev/null +++ b/genius_invocation/card/character/characters/Navia.py @@ -0,0 +1,236 @@ +from genius_invocation.card.character.import_head import * +from genius_invocation.card.action.base import ActionCard + + +class CrystalShrapnel(ActionCard): + id: int = 160871 + name = "Crystal Shrapnel" + name_ch = "裂晶弹片" + cost_num = 1 + cost_type = CostType.WHITE + card_type = ActionCardType.EVENT + + def __init__(self) -> None: + super().__init__() + + def on_played(self, game: 'GeniusGame'): + dmg = Damage.create_damage( + game, + damage_type=SkillType.OTHER, + main_damage_element=ElementType.PHYSICAL, + main_damage=1, + piercing_damage=0, + damage_from=self.zone, + damage_to=get_active_character(game, 1-self.zone.from_player.index), + ) + game.add_damage(dmg) + game.resolve_damage() + self.zone.from_player.get_card(num=1) + +class MutualAssistanceNetwork(CharacterSkill): + id = 160804 + name = 'Mutual Assistance Network' + name_ch = '互助关系网' + def on_call(self, game:'GeniusGame'): + self.from_character.from_player.card_zone.return_card([CrystalShrapnel() for i in range(3)]) + +class BluntRefusal(NormalAttack): + id: int = 160801 + type: SkillType = SkillType.NORMAL_ATTACK + name = "Blunt Refusal" + name_ch = "直率的辞绝" + damage_type: SkillType = SkillType.NORMAL_ATTACK + main_damage_element: ElementType = ElementType.PHYSICAL + main_damage: int = 2 + piercing_damage: int = 0 + cost = [{ + 'cost_num': 1, + 'cost_type': CostType.GEO + }, + { + 'cost_num': 2, + 'cost_type': CostType.BLACK + } + ] + energy_cost: int = 0 + energy_gain: int = 1 + + def __init__(self, from_character: 'Character'): + super().__init__(from_character) + + def on_call(self, game: 'GeniusGame'): + super().on_call(game) + self.resolve_damage(game) + self.gain_energy(game) + game.manager.invoke(EventType.AFTER_USE_SKILL, game) + +class GEOElementalInfusion(Combat_Status): + name = "GEO Elemental Infusion" + name_ch = "岩元素附魔" + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character = None): + super().__init__(game, from_player, from_character) + self.max_usage = 2 + self.current_usage = 2 + + def update(self): + self.current_usage = self.max_usage + + def on_infuse(self, game:'GeniusGame'): + if game.current_damage.damage_from == self.from_character: + if game.current_damage.main_damage_element == ElementType.PHYSICAL: + game.current_damage.main_damage_element = ElementType.PYRO + + def on_end(self, game:'GeniusGame'): + if game.active_player == self.from_player: + self.current_usage -= 1 + if self.current_usage <= 0: + self.on_destroy(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.INFUSION, ZoneType.ACTIVE_ZONE, self.on_infuse), + (EventType.FINAL_END, ZoneType.ACTIVE_ZONE, self.on_end) + ] + +class CeremonialCrystalshot(ElementalSkill): + id: int = 160802 + name = "Ceremonial Crystalshot" + name_ch = "典仪式晶火" + type: SkillType = SkillType.ELEMENTAL_SKILL + damage_type: SkillType = SkillType.ELEMENTAL_SKILL + main_damage_element: ElementType = ElementType.GEO + main_damage: int = 3 + piercing_damage: int = 0 + cost = [ + { + 'cost_num': 3, + 'cost_type': CostType.GEO + }, + ] + energy_cost: int = 0 + energy_gain: int = 1 + def __init__(self, from_character: 'Character'): + super().__init__(from_character) + + def on_call(self, game: 'GeniusGame'): + super().on_call(game) + cards = self.from_character.from_player.hand_zone.discard_card_by_name(name="Crystal Shrapnel", num=5) + self.resolve_damage(game, add_main_damage=len(cards)) + self.gain_energy(game) + self.add_status(game, GEOElementalInfusion) + self.from_character.from_player.get_card(num=len(cards)) + game.manager.invoke(EventType.AFTER_USE_SKILL, game) + +class RosulaDorataSalute(Summon): + id = 160811 + name: str = "Rosula Dorata Salute" + name_ch = "金花礼炮" + removable = True + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character:'Character'=None): + super().__init__(game, from_player, from_character) + self.usage = 2 + self.current_usage = self.usage + + def update(self): + self.current_usage = max(self.current_usage, self.usage) + + def on_end_phase(self, game: 'GeniusGame'): + if game.active_player == self.from_player: + dmg = Damage.create_damage( + game, + damage_type=SkillType.SUMMON, + main_damage_element=ElementType.GEO, + main_damage=1, + piercing_damage=0, + damage_from=self, + damage_to=get_opponent_active_character(game), + ) + game.add_damage(dmg) + game.resolve_damage() + + cards = self.from_player.card_zone.find_card_by_name("Crystal Shrapnel", num=1) + self.from_player.hand_zone.add(cards) + + self.current_usage -= 1 + if(self.current_usage <= 0): + self.on_destroy(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.END_PHASE, ZoneType.SUMMON_ZONE, self.on_end_phase), + ] + +class SingingSalute(ElementalBurst): + id = 160803 + name="As the Sunlit Sky's Singing Salute" + name_ch = "如霰澄天的鸣礼" + type: SkillType = SkillType.ELEMENTAL_BURST + + # damage + damage_type: SkillType = SkillType.ELEMENTAL_BURST + main_damage_element: ElementType = ElementType.GEO + main_damage: int = 1 + piercing_damage: int = 1 + + # cost + cost = [ + { + 'cost_num': 3, + 'cost_type': CostType.PYRO + } + ] + energy_cost: int = 2 + energy_gain: int = 0 + + def __init__(self, from_character: 'Character') -> None: + super().__init__(from_character) + + def on_call(self, game: 'GeniusGame'): + super().on_call(game) + self.consume_energy(game) + self.resolve_damage(game) + self.generate_summon(game, RosulaDorataSalute) + self.from_character.from_player.hand_zone.add([CrystalShrapnel()]) + game.manager.invoke(EventType.AFTER_USE_SKILL, game) + +class Navia(Character): + id = 1608 + name = "Navia" + name_ch = "娜维娅" + time = 4.8 + element = ElementType.GEO + weapon_type: WeaponType = WeaponType.CLAYMORE + country: CountryType = CountryType.FONTAINE + + init_health_point: int = 10 + max_health_point: int = 10 + skill_list = [BluntRefusal, CeremonialCrystalshot, SingingSalute] + max_power: int = 2 + + def init_state(self, game: 'GeniusGame'): + self.listen_event(game, EventType.DAMAGE_ADD_AFTER_REACTION, ZoneType.CHARACTER_ZONE, self.on_reaction) + + def __init__(self, game: 'GeniusGame', zone: 'CharacterZone', from_player: 'GeniusPlayer', index:int, from_character = None, talent = False): + super().__init__(game, zone, from_player, index, from_character) + self.talent = talent + self.power = 0 + self.talent_skill = self.skills[1] + self.passive_skill = MutualAssistanceNetwork(self) + self.talent_round_usage = 1 + + def on_reaction(self, game: 'GeniusGame'): + if game.current_damage.damage_to.from_player.index == 1 - self.from_player.index: + if game.current_damage.reaction == ElementalReactionType.Crystallize: + self.passive_skill.on_reaction(game) + + def after_use_skill(self, game: 'GeniusGame'): + if game.current_skill.from_character == self: + if self.talent: + if self.talent_round_usage > 0: + cards = self.from_player.card_zone.find_card_by_name("Crystal Shrapnel", num=2) + self.from_player.hand_zone.add(cards) + self.talent_round_usage -= 1 + + def listen_talent_events(self, game: 'GeniusGame'): + self.listen_event(game, EventType.AFTER_USE_SKILL, ZoneType.CHARACTER_ZONE, self.after_use_skill) + diff --git a/genius_invocation/card/character/characters/Qiqi.py b/genius_invocation/card/character/characters/Qiqi.py index 0a5acfe3..720a7bf2 100644 --- a/genius_invocation/card/character/characters/Qiqi.py +++ b/genius_invocation/card/character/characters/Qiqi.py @@ -115,7 +115,7 @@ def on_call(self, game: 'GeniusGame'): char = self.from_character.from_player.character_list[i] if not char.is_alive: char.revive(game) - char.health_point = 2 + char.heal(heal=2, game=game) game.manager.invoke(EventType.AFTER_USE_SKILL, game) diff --git a/genius_invocation/card/character/characters/Yaoyao.py b/genius_invocation/card/character/characters/Yaoyao.py index 69f3030b..9b0a47d6 100644 --- a/genius_invocation/card/character/characters/Yaoyao.py +++ b/genius_invocation/card/character/characters/Yaoyao.py @@ -122,7 +122,7 @@ def update(self): self.current_usage = max(self.current_usage, self.usage) def on_swich(self, game: 'GeniusGame'): - if game.active_player == self.from_player: + if game.current_switch['from'].from_player == self.from_player: damage = 1 heal = 1 diff --git a/genius_invocation/card/character/import_head.py b/genius_invocation/card/character/import_head.py index 9c546cdc..4cef05b1 100644 --- a/genius_invocation/card/character/import_head.py +++ b/genius_invocation/card/character/import_head.py @@ -3,6 +3,7 @@ from genius_invocation.utils import * from typing import TYPE_CHECKING, List, Tuple from genius_invocation.event.damage import Damage +from genius_invocation.event.heal import Heal, BondofLife from genius_invocation.entity.character import Character from genius_invocation.entity.status import Status, Combat_Status, Shield, Combat_Shield from genius_invocation.entity.summon import Summon diff --git a/genius_invocation/entity/character.py b/genius_invocation/entity/character.py index 0ad51f2e..6fc31d01 100644 --- a/genius_invocation/entity/character.py +++ b/genius_invocation/entity/character.py @@ -43,10 +43,10 @@ class Character(Entity): def balance_adjustment(): log = {} return log - + def get_element(self): return [self.element] - + def init_state(self, game: 'GeniusGame'): ''' 游戏开始时的被动技能 @@ -128,13 +128,15 @@ def __init__(self, game: 'GeniusGame', character_zone:'CharacterZone', from_play super().__init__(game, from_player, from_character) self.init_state(game) - def heal(self, heal: int, game:'GeniusGame'): + def heal(self, heal: int, game:'GeniusGame', heal_type=HealType.HEAL): if self.is_alive: + game.current_heal = Heal(heal=heal, target_character=self, heal_type=heal_type) + game.manager.invoke(EventType.ON_HEAL, game) self.health_point += heal if self.health_point > self.max_health_point: heal = heal + self.health_point - self.max_health_point self.health_point = self.max_health_point - game.current_heal = Heal(heal=heal, target_character=self) + game.current_heal.heal_num = heal game.manager.invoke(EventType.AFTER_HEAL, game) def get_power(self, power:int): @@ -165,7 +167,7 @@ def revive(self, game: 'GeniusGame'): # Basic revive. assert self.is_alive == False self.is_alive = True - self.health_point = 1 + self.health_point = 0 def show(self): return str(self.health_point) diff --git a/genius_invocation/event/damage/damage.py b/genius_invocation/event/damage/damage.py index 8a6c3817..1b55ead7 100644 --- a/genius_invocation/event/damage/damage.py +++ b/genius_invocation/event/damage/damage.py @@ -16,6 +16,7 @@ def __init__(self, damage_type: 'SkillType', main_damage_element: 'ElementType', self.damage_type: SkillType = damage_type self.main_damage_element: ElementType = main_damage_element self.main_damage: int = main_damage + self.max_main_damage: int = main_damage # 愚人众·霜役人被动结算 self.piercing_damage: int = piercing_damage self.damage_multiply = damage_multiply @@ -81,6 +82,7 @@ def damage_add(self, game: 'GeniusGame'): def damage_dealing(self, game: 'GeniusGame'): game.manager.invoke(EventType.DEALING_DAMAGE, game) self.main_damage = self.main_damage * self.damage_multiply + self.max_main_damage = self.main_damage def damage_divide(self, game: 'GeniusGame'): game.manager.invoke(EventType.DIVIDE_DAMAGE, game) def damage_execute(self, game: 'GeniusGame'): diff --git a/genius_invocation/event/heal.py b/genius_invocation/event/heal.py index e54e093d..0943d00b 100644 --- a/genius_invocation/event/heal.py +++ b/genius_invocation/event/heal.py @@ -7,14 +7,40 @@ class Heal: def __init__( - self, - heal: int, - target_character: 'Character' + self, + heal: int, + target_character: 'Character', + heal_type: HealType = HealType.HEAL ) -> None: self.heal_to_character = target_character self.heal_to_player = target_character.from_player self.heal_num = heal + self.heal_type = heal_type + +class BondofLife(Status): + id: int = 23 + name: str = "Bond of Life" + name_ch = "生命之契" + def __init__(self, game: 'GeniusGame', from_player: 'GeniusPlayer', from_character=None, usgae=1): + super().__init__(game, from_player, from_character) + self.usage = usgae + + def update(self, usage=1): + self.usage += usage + + def on_heal(self, game: 'GeniusGame'): + if game.current_heal.heal_to_character == self.from_character: + target_heal = max(0, game.current_heal.heal_num - self.usage) + self.usage = max(0, self.usage - game.current_heal.heal_num) + game.current_heal.heal_num = target_heal + if self.usage == 0: + self.on_destroy(game) + + def update_listener_list(self): + self.listeners = [ + (EventType.ON_HEAL, ZoneType.CHARACTER_ZONE, self.on_heal) + ] + - diff --git a/genius_invocation/game/game.py b/genius_invocation/game/game.py index 6a563694..45dcc215 100644 --- a/genius_invocation/game/game.py +++ b/genius_invocation/game/game.py @@ -56,6 +56,7 @@ def __init__(self, player0_deck, player1_deck, seed=None, is_omni=False, is_read self.current_die: Character = None self.current_heal: Heal = None self.current_dice: Dice = None + self.current_player: GeniusPlayer = None self.current_action: Action = None self.current_damage: Damage = None self.current_switch: Dict[str, Character] = {"from": None, "to": None} @@ -72,7 +73,7 @@ def __init__(self, player0_deck, player1_deck, seed=None, is_omni=False, is_read self.is_end: bool = False self.is_overload:GeniusPlayer = None self.can_play_card = True - + if not self.is_read: self.init_game() @@ -455,7 +456,7 @@ def read_game(message): game.round = message.round return game - + ''' TODO: code for encoding states 思路 diff --git a/genius_invocation/game/zone.py b/genius_invocation/game/zone.py index b1c05c41..16f4a544 100644 --- a/genius_invocation/game/zone.py +++ b/genius_invocation/game/zone.py @@ -42,7 +42,7 @@ class DiceZone: 骰子区 ''' def __init__(self, game: 'GeniusGame', player: 'GeniusPlayer') -> None: - self.player = player + self.from_player = player ''' 我们用一个[16, 9]的数组来维护骰子 ''' @@ -60,7 +60,7 @@ def get_sort_map(self): sort_map[DiceType.OMNI.value] = 4000 # 万能最优先 # 有效骰子优先 - for character in self.player.character_list: + for character in self.from_player.character_list: if character.is_alive: for element in character.get_element(): sort_map[ElementToDice[element].value] += 200 @@ -81,6 +81,11 @@ def add(self, dices: List): ''' if dices == []: return + for i in range(len(dices)): + self.game.current_player = self.from_player + self.game.manager.invoke(EventType.ON_GET_DICE, self.game) + self.game.current_player = None + dices = sorted(dices, key=lambda x:self.sort_map[x], reverse=True) for idx, dice in enumerate(dices): if dice != DiceType.OMNI.value: @@ -248,14 +253,14 @@ def __init__(self, game: 'GeniusGame', player: 'GeniusPlayer', card: List) -> No self.card_type.append(self.card[-1].card_type) # 随机固定牌序 self.game = game - self.player = player + self.from_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.current_get_card = GetCard(from_player=self.from_player, num=num) self.game.manager.invoke(EventType.ON_GET_CARD, self.game) self.game.current_get_card = None @@ -343,6 +348,7 @@ def return_card(self, card_list: List): ''' for card in card_list: idx = self.game.random.randint(0, self.num()+1) + card.zone = self self.card.insert(idx, card) def insert_evenly(self, card_list: List): @@ -364,7 +370,9 @@ def insert_randomly(self, card_list: List, num=-1): insert_indices = random.sample(range(0, num+len(card_list)), len(card_list)) insert_indices.sort() for index in insert_indices: - self.card.insert(index, card_list.pop()) + card = card_list.pop() + card.zone = self + self.card.insert(index, card) def discard_card(self, idx): ''' @@ -372,9 +380,10 @@ def discard_card(self, idx): ''' card: ActionCard = self.card.pop(idx) card.on_discard(self.game) + card.zone = None - self.player.tune_or_discard_cards.append(card) - self.player.round_discard_cards += 1 + self.from_player.tune_or_discard_cards.append(card) + self.from_player.round_discard_cards += 1 self.game.invoke(EventType.ON_DISCARD_CARD, self.game) return card @@ -435,6 +444,7 @@ class SupportZone: ''' def __init__(self, game: 'GeniusGame', player: 'GeniusPlayer') -> None: self.game = game + self.from_player = player self.space: List[Support] = [] self.distroy_count = 0 @@ -462,6 +472,9 @@ def add_entity(self, entity, idx, **kwargs): self.space[idx].on_destroy(self.game) self.space.append(entity) + def add_entity_by_name(self, entity_name, idx, **kwargs): + entity = eval(entity_name)().entity(self.game, self.from_player) + self.add_entity(entity, self.num(), **kwargs) def num(self): return len(self.space) @@ -614,10 +627,18 @@ def remove(self, idx: List): if type(idx) == int: idx = [idx] idx.sort(reverse=True) - return [self.card.pop(i) for i in idx] + + remove_list = [] + for i in idx: + card = self.card.pop(i) + card.zone = None + remove_list.append(card) + return remove_list def use(self, idx: int): - return self.card.pop(idx) + card = self.card.pop(idx) + card.zone = None + return card def add(self, cards: List['ActionCard']): if cards == []: @@ -626,6 +647,7 @@ def add(self, cards: List['ActionCard']): if len(self.card)>= MAX_HANDCARD: break self.card.append(card) + card.zone = self self.card = sorted(self.card, key=lambda card: card.id) def add_card_by_name(self, card_names): @@ -656,7 +678,10 @@ def discard_card(self, idx): ''' 舍弃牌 ''' + if idx == None: + return None card: ActionCard = self.card.pop(idx) + card.zone = None card.on_discard(self.game) self.from_player.tune_or_discard_cards.append(card) diff --git a/genius_invocation/main.py b/genius_invocation/main.py index 016f99e5..13b3de8f 100644 --- a/genius_invocation/main.py +++ b/genius_invocation/main.py @@ -82,7 +82,10 @@ def test_select(): package_dirs = ["./card/character/characters","./card/action/support/companion", "./card/action/support/item","./card/action/support/location", "./card/action/event/events","./card/action/event/foods", - "./card/action/event/elemental_resonance", "./card/action/event/arcane_legend", + "./card/action/event/elemental_resonance_dice", + "./card/action/event/elemental_resonance_event", + "./card/action/event/country_resonance", + "./card/action/event/arcane_legend", "./card/action/equipment/artifact/artifacts", "./card/action/equipment/talent/talents", "./card/action/equipment/weapon/weapons"] diff --git a/genius_invocation/utils.py b/genius_invocation/utils.py index ae733a21..a56dd4de 100644 --- a/genius_invocation/utils.py +++ b/genius_invocation/utils.py @@ -175,6 +175,17 @@ class EventType(Enum): ON_DISCARD_CARD = 30 # 获得牌 ON_GET_CARD = 31 + # 获得骰子 + ON_GET_DICE = 32 + # 治疗时 + ON_HEAL = 33 + +class HealType(Enum): + HEAL = 0 + REVIVE = 1 + MAX_HEALTH = 2 + HEALTH_ASSIGNMENT = 3 + class SwitchType(Enum): CHANGE_CHARACTER = 0 @@ -395,4 +406,44 @@ def max_count_card(cards: List['ActionCard']) -> int: for idx, card in enumerate(cards): if card.calculate_dice() == max_count: max_idx.append(idx) - return random.choice(max_idx) \ No newline at end of file + if len(max_idx) == 0: + return None + return random.choice(max_idx) + +def max_dmg_taken(from_player: 'GeniusPlayer'): + max_dmg_taken = -1 + max_taken_char = None + ls: List[int] = [] + id = from_player.active_idx + for i in range(from_player.character_num): + ls.append(id) + id += 1 + if id >= from_player.character_num: + id = 0 + + for i in ls: + char = from_player.character_list[i] + dmg_taken = char.max_health_point - char.health_point + if dmg_taken > max_dmg_taken: + max_dmg_taken = dmg_taken + max_taken_char = char + return max_taken_char + +def min_dmg_taken(from_player: 'GeniusPlayer'): + min_dmg_taken = 10000 + min_taken_char = None + ls: List[int] = [] + id = from_player.active_idx + for i in range(from_player.character_num): + ls.append(id) + id += 1 + if id >= from_player.character_num: + id = 0 + + for i in ls: + char = from_player.character_list[i] + dmg_taken = char.max_health_point - char.health_point + if dmg_taken < min_dmg_taken: + min_dmg_taken = dmg_taken + min_taken_char = char + return min_taken_char \ No newline at end of file