1
0

Add Fireball Scoll, completing part 8

This commit is contained in:
Timothy Warren 2022-01-18 13:26:26 -05:00
parent 621d4780e8
commit a1e6125c34
4 changed files with 85 additions and 1 deletions

View File

@ -8,7 +8,7 @@ import components.ai
import components.inventory import components.inventory
from components.base_component import BaseComponent from components.base_component import BaseComponent
from exceptions import Impossible from exceptions import Impossible
from input_handlers import SingleRangedAttackHandler from input_handlers import AreaRangedAttackHandler, SingleRangedAttackHandler
if TYPE_CHECKING: if TYPE_CHECKING:
from entity import Actor, Item from entity import Actor, Item
@ -94,6 +94,45 @@ class HealingConsumable(Consumable):
raise Impossible(f"Your health is already full.") raise Impossible(f"Your health is already full.")
class FireballDamageConsumable(Consumable):
def __init__(self, damage: int, radius: int):
self.damage = damage
self.radius = radius
def get_action(self, consumer: Actor) -> Optional[actions.Action]:
self.engine.message_log.add_message(
"Select a target location.",
color.needs_target
)
self.engine.event_handler = AreaRangedAttackHandler(
self.engine,
self.radius,
lambda xy: actions.ItemAction(consumer, self.parent, xy),
)
return None
def activate(self, action: actions.ItemAction) -> None:
target_xy = action.target_xy
if not self.engine.game_map.visible[target_xy]:
raise Impossible("You cannot target an area that you cannot see.")
targets_hit = False
for actor in self.engine.game_map.actors:
if actor.distance(*target_xy) <= self.radius:
self.engine.message_log.add_message(
f"The {actor.name} is engulfed in a fiery explosion, taking {self.damage} damage!"
)
actor.fighter.take_damage(self.damage)
targets_hit = True
if not targets_hit:
raise Impossible("There are no targets in the radius.")
self.consume()
class LightningDamageConsumable(Consumable): class LightningDamageConsumable(Consumable):
def __init__(self, damage: int, maximum_range: int): def __init__(self, damage: int, maximum_range: int):
self.damage = damage self.damage = damage

View File

@ -36,6 +36,12 @@ confusion_scroll = Item(
name="Confusion Scroll", name="Confusion Scroll",
consumable=consumable.ConfusionConsumable(number_of_turns=10), consumable=consumable.ConfusionConsumable(number_of_turns=10),
) )
fireball_scroll = Item(
char="~",
color=(255, 0, 0),
name="Fireball Scroll",
consumable=consumable.FireballDamageConsumable(damage=12, radius=3),
)
health_potion = Item( health_potion = Item(
char="!", char="!",
color=(127, 0, 255), color=(127, 0, 255),

View File

@ -310,6 +310,43 @@ class SingleRangedAttackHandler(SelectIndexHandler):
return self.callback((x, y)) return self.callback((x, y))
class AreaRangedAttackHandler(SelectIndexHandler):
"""
Handles targeting an area within a given radius.
Any entity within the area will be affected.
"""
def __init__(
self,
engine: Engine,
radius: int,
callback: Callable[[Tuple[int, int]], Optional[Action]]
):
super().__init__(engine)
self.radius = radius
self.callback = callback
def on_render(self, console: tcod.Console) -> None:
"""Highlight the tile under the cursor."""
super().on_render(console)
x, y = self.engine.mouse_location
# Draw a rectangle around the targeted area, so the player can see the affected tiles.
console.draw_frame(
x=x - self.radius - 1,
y=y - self.radius - 1,
width=self.radius ** 2,
height=self.radius ** 2,
fg=color.red,
clear=False,
)
def on_index_selected(self, x: int, y: int) -> Optional[Action]:
return self.callback((x, y))
class MainGameEventHandler(EventHandler): class MainGameEventHandler(EventHandler):
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[Action]: def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[Action]:
action: Optional[Action] = None action: Optional[Action] = None

View File

@ -70,6 +70,8 @@ def place_entities(
if item_chance < 0.7: if item_chance < 0.7:
entity_factories.health_potion.spawn(dungeon, x, y) entity_factories.health_potion.spawn(dungeon, x, y)
elif item_chance < 0.8:
entity_factories.fireball_scroll.spawn(dungeon, x, y)
elif item_chance < 0.9: elif item_chance < 0.9:
entity_factories.confusion_scroll.spawn(dungeon, x, y) entity_factories.confusion_scroll.spawn(dungeon, x, y)
else: else: