Skip to content

Commit

Permalink
feat: implement hu tao
Browse files Browse the repository at this point in the history
  • Loading branch information
zyr17 committed Sep 14, 2023
1 parent e940ed1 commit 2129a26
Show file tree
Hide file tree
Showing 3 changed files with 251 additions and 2 deletions.
7 changes: 5 additions & 2 deletions server/charactor/pyro/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
from .yoimiya import Yoimiya, NaganoharaMeteorSwarm
from .xiangling import Xiangling, Guoba, Crossfire
from .yanfei import Yanfei, RightOfFinalInterpretation
from .hu_tao import HuTao, SanguineRouge


PyroCharactors = FatuiPyroAgent | Klee | Bennett | Yoimiya | Xiangling | Yanfei
PyroCharactors = (
FatuiPyroAgent | Klee | Bennett | Yoimiya | Xiangling | Yanfei | HuTao
)
SummonsOfPyroCharactors = Guoba | Guoba
PyroCharactorTalents = (
PaidinFull | PoundingSurprise | GrandExpectation | NaganoharaMeteorSwarm
| Crossfire | RightOfFinalInterpretation
| Crossfire | RightOfFinalInterpretation | SanguineRouge
)
153 changes: 153 additions & 0 deletions server/charactor/pyro/hu_tao.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
from typing import Any, List, Literal

from ...modifiable_values import DamageIncreaseValue, DamageValue
from ...action import Actions, MakeDamageAction
from ...struct import Cost

from ...consts import (
DamageElementalType, DamageType, DieColor, ElementType, FactionType,
ObjectPositionType, WeaponType
)
from ..charactor_base import (
ElementalBurstBase, ElementalSkillBase,
PhysicalNormalAttackBase, CharactorBase, SkillTalent
)


# Skills


class GuideToAfterlife(ElementalSkillBase):
name: Literal['Guide to Afterlife'] = 'Guide to Afterlife'
desc: str = '''This character gains Paramita Papilio.'''
damage: int = 0
damage_type: DamageElementalType = DamageElementalType.PIERCING
cost: Cost = Cost(
elemental_dice_color = DieColor.PYRO,
elemental_dice_number = 2
)

def get_actions(self, match: Any) -> List[Actions]:
"""
gain charge and create status
"""
return [
self.charge_self(1),
self.create_charactor_status('Paramita Papilio'),
]


class SpiritSoother(ElementalBurstBase):
name: Literal['Spirit Soother'] = 'Spirit Soother'
desc: str = (
"Deals 4 Pyro DMG, heals herself for 2 HP. If this character's HP is "
"no more than 6, DMG dealt and Healing are increased by 1."
)
damage: int = 4
damage_type: DamageElementalType = DamageElementalType.PYRO
cost: Cost = Cost(
elemental_dice_color = DieColor.PYRO,
elemental_dice_number = 3,
charge = 3
)

def get_actions(self, match: Any) -> List[Actions]:
"""
Check if hp <= 6. If so, increase damage and heal
"""
charactor = match.player_tables[self.position.player_idx].charactors[
self.position.charactor_idx]
heal = 2
if charactor.hp <= 6:
self.damage = 5
heal = 3
ret = super().get_actions(match)
self.damage = 4
ret.append(MakeDamageAction(
source_player_idx = self.position.player_idx,
target_player_idx = self.position.player_idx,
damage_value_list = [
DamageValue(
position = self.position,
damage_type = DamageType.HEAL,
target_position = charactor.position,
damage = -heal,
damage_elemental_type = DamageElementalType.HEAL,
cost = Cost()
)
]
))
return ret

# Talents


class SanguineRouge(SkillTalent):
name: Literal['Sanguine Rouge']
desc: str = (
'Combat Action: When your active character is Hu Tao, equip this '
'card. After Hu Tao equips this card, immediately use Guide to '
'Afterlife once. When your Hu Tao, who has this card equipped, has no '
'more than 6 HP, Pyro DMG dealt +1.'
)
version: Literal['3.7'] = '3.7'
charactor_name: Literal['Hu Tao'] = 'Hu Tao'
cost: Cost = Cost(
elemental_dice_color = DieColor.PYRO,
elemental_dice_number = 2
)
skill: GuideToAfterlife = GuideToAfterlife()

def value_modifier_DAMAGE_INCREASE(
self, value: DamageIncreaseValue, match: Any,
mode: Literal['TEST', 'REAL'],
) -> DamageIncreaseValue:
if self.position.area != ObjectPositionType.CHARACTOR:
# not equipped
return value
if not value.is_corresponding_charactor_use_damage_skill(
self.position, match, None
):
# not self use damage skill
return value
if value.damage_elemental_type != DamageElementalType.PYRO:
# not pyro damage
return value
charactor = match.player_tables[self.position.player_idx].charactors[
self.position.charactor_idx]
if charactor.hp > 6:
# hp > 6
return value
# increase damage
value.damage += 1
return value


# charactor base


class HuTao(CharactorBase):
name: Literal['Hu Tao']
version: Literal['3.7'] = '3.7'
desc: str = '''"Fragrance in Thaw" Hu Tao'''
element: ElementType = ElementType.PYRO
max_hp: int = 10
max_charge: int = 3
skills: List[
PhysicalNormalAttackBase | GuideToAfterlife | SpiritSoother
] = []
faction: List[FactionType] = [
FactionType.LIYUE
]
weapon_type: WeaponType = WeaponType.POLEARM
talent: SanguineRouge | None = None

def _init_skills(self) -> None:
self.skills = [
PhysicalNormalAttackBase(
name = 'Secret Spear of Wangsheng',
cost = PhysicalNormalAttackBase.get_cost(self.element),
),
GuideToAfterlife(),
SpiritSoother()
]
93 changes: 93 additions & 0 deletions server/status/charactor_status/pyro_charactors.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,99 @@ def value_modifier_DAMAGE_INCREASE(
return value


class ParamitaPapilio(ElementalInfusionCharactorStatus, RoundCharactorStatus):
name: Literal['Paramita Papilio'] = 'Paramita Papilio'
desc: str = (
'The character to which this is attached has their Physical DMG dealt '
'converted to Pyro DMG, and they will deal +1 Pyro DMG. When the '
'character to which this is attached uses a Charged Attack: Apply '
'Blood Blossom to target character.'
)
version: Literal['3.7'] = '3.7'
usage: int = 2
max_usage: int = 2

infused_elemental_type: DamageElementalType = DamageElementalType.PYRO

def value_modifier_DAMAGE_INCREASE(
self, value: DamageIncreaseValue, match: Any,
mode: Literal['TEST', 'REAL'],
) -> DamageIncreaseValue:
if not value.is_corresponding_charactor_use_damage_skill(
self.position, match, None
):
# not self use damage skill
return value
if (
value.damage_elemental_type != DamageElementalType.PYRO
): # pragma: no cover
# not pyro damage
return value
# increase damage
value.damage += 1
return value

def event_handler_SKILL_END(
self, event: SkillEndEventArguments, match: Any
) -> List[CreateObjectAction]:
"""
If self use charged attack, create blood blossom on target
"""
if not self.position.check_position_valid(
event.action.position, match, player_idx_same = True,
charactor_idx_same = True, target_area = ObjectPositionType.SKILL
):
# not self use skill
return []
if not (
event.action.skill_type == SkillType.NORMAL_ATTACK
and match.player_tables[self.position.player_idx].charge_satisfied
):
# not charged attack
return []
return [CreateObjectAction(
object_position = event.action.target_position.set_area(
ObjectPositionType.CHARACTOR_STATUS),
object_name = 'Blood Blossom',
object_arguments = {}
)]


# Usage status, will not disappear until usage is 0
class BloodBlossom(UsageCharactorStatus):
name: Literal['Blood Blossom'] = 'Blood Blossom'
desc: str = (
'End Phase: Deal 1 Pyro DMG to the character to which this is '
'attached.'
)
version: Literal['3.7'] = '3.7'
usage: int = 1
max_usage: int = 1

def event_handler_ROUND_END(
self, event: RoundEndEventArguments, match: Any
) -> List[MakeDamageAction]:
assert self.usage > 0
self.usage -= 1
charactor = match.player_tables[self.position.player_idx].charactors[
self.position.charactor_idx]
return [MakeDamageAction(
source_player_idx = self.position.player_idx,
target_player_idx = self.position.player_idx,
damage_value_list = [
DamageValue(
position = self.position,
damage_type = DamageType.DAMAGE,
target_position = charactor.position,
damage = 1,
damage_elemental_type = DamageElementalType.PYRO,
cost = Cost()
)
]
)]


PyroCharactorStatus = (
Stealth | ExplosiveSpark | NiwabiEnshou | Brilliance | ScarletSeal
| ParamitaPapilio | BloodBlossom
)

0 comments on commit 2129a26

Please sign in to comment.