|
4 | 4 |
|
5 | 5 | import game.actions |
6 | 6 | import game.color |
| 7 | +import game.components.ai |
7 | 8 | import game.components.base_component |
8 | 9 | import game.exceptions |
| 10 | +import game.input_handlers |
9 | 11 |
|
10 | 12 | if TYPE_CHECKING: |
11 | 13 | import game.entity |
@@ -51,3 +53,100 @@ def activate(self, action: game.actions.ItemAction) -> None: |
51 | 53 | self.consume() |
52 | 54 | else: |
53 | 55 | raise game.exceptions.Impossible("Your health is already full.") |
| 56 | + |
| 57 | + |
| 58 | +class LightningDamageConsumable(Consumable): |
| 59 | + def __init__(self, damage: int, maximum_range: int): |
| 60 | + self.damage = damage |
| 61 | + self.maximum_range = maximum_range |
| 62 | + |
| 63 | + def activate(self, action: game.actions.ItemAction) -> None: |
| 64 | + consumer = action.entity |
| 65 | + target = None |
| 66 | + closest_distance = self.maximum_range + 1.0 |
| 67 | + |
| 68 | + for actor in self.engine.game_map.actors: |
| 69 | + if actor is not consumer and self.parent.gamemap.visible[actor.x, actor.y]: |
| 70 | + distance = consumer.distance(actor.x, actor.y) |
| 71 | + |
| 72 | + if distance < closest_distance: |
| 73 | + target = actor |
| 74 | + closest_distance = distance |
| 75 | + |
| 76 | + if target: |
| 77 | + self.engine.message_log.add_message( |
| 78 | + f"A lighting bolt strikes the {target.name} with a loud thunder, for {self.damage} damage!" |
| 79 | + ) |
| 80 | + target.fighter.take_damage(self.damage) |
| 81 | + self.consume() |
| 82 | + else: |
| 83 | + raise game.exceptions.Impossible("No enemy is close enough to strike.") |
| 84 | + |
| 85 | + |
| 86 | +class ConfusionConsumable(Consumable): |
| 87 | + def __init__(self, number_of_turns: int): |
| 88 | + self.number_of_turns = number_of_turns |
| 89 | + |
| 90 | + def get_action(self, consumer: game.entity.Actor) -> Optional[game.input_handlers.ActionOrHandler]: |
| 91 | + self.engine.message_log.add_message( |
| 92 | + "Select a target location.", game.color.needs_target |
| 93 | + ) |
| 94 | + return game.input_handlers.SingleRangedAttackHandler( |
| 95 | + self.engine, |
| 96 | + callback=lambda xy: game.actions.ItemAction(consumer, self.parent, xy), |
| 97 | + ) |
| 98 | + |
| 99 | + def activate(self, action: game.actions.ItemAction) -> None: |
| 100 | + consumer = action.entity |
| 101 | + target = action.target_actor |
| 102 | + |
| 103 | + if not self.engine.game_map.visible[action.target_xy]: |
| 104 | + raise game.exceptions.Impossible("You cannot target an area that you cannot see.") |
| 105 | + if not target: |
| 106 | + raise game.exceptions.Impossible("You must select an enemy to target.") |
| 107 | + if target is consumer: |
| 108 | + raise game.exceptions.Impossible("You cannot confuse yourself!") |
| 109 | + |
| 110 | + self.engine.message_log.add_message( |
| 111 | + f"The eyes of the {target.name} look vacant, as it starts to stumble around!", |
| 112 | + game.color.status_effect_applied, |
| 113 | + ) |
| 114 | + target.ai = game.components.ai.ConfusedEnemy( |
| 115 | + entity=target, previous_ai=target.ai, turns_remaining=self.number_of_turns, |
| 116 | + ) |
| 117 | + self.consume() |
| 118 | + |
| 119 | + |
| 120 | +class FireballDamageConsumable(Consumable): |
| 121 | + def __init__(self, damage: int, radius: int): |
| 122 | + self.damage = damage |
| 123 | + self.radius = radius |
| 124 | + |
| 125 | + def get_action(self, consumer: game.entity.Actor) -> Optional[game.input_handlers.ActionOrHandler]: |
| 126 | + self.engine.message_log.add_message( |
| 127 | + "Select a target location.", game.color.needs_target |
| 128 | + ) |
| 129 | + return game.input_handlers.AreaRangedAttackHandler( |
| 130 | + self.engine, |
| 131 | + radius=self.radius, |
| 132 | + callback=lambda xy: game.actions.ItemAction(consumer, self.parent, xy), |
| 133 | + ) |
| 134 | + |
| 135 | + def activate(self, action: game.actions.ItemAction) -> None: |
| 136 | + target_xy = action.target_xy |
| 137 | + |
| 138 | + if not self.engine.game_map.visible[target_xy]: |
| 139 | + raise game.exceptions.Impossible("You cannot target an area that you cannot see.") |
| 140 | + |
| 141 | + targets_hit = False |
| 142 | + for actor in self.engine.game_map.actors: |
| 143 | + if actor.distance(*target_xy) <= self.radius: |
| 144 | + self.engine.message_log.add_message( |
| 145 | + f"The {actor.name} is engulfed in a fiery explosion, taking {self.damage} damage!" |
| 146 | + ) |
| 147 | + actor.fighter.take_damage(self.damage) |
| 148 | + targets_hit = True |
| 149 | + |
| 150 | + if not targets_hit: |
| 151 | + raise game.exceptions.Impossible("There are no targets in the radius.") |
| 152 | + self.consume() |
0 commit comments