Add Fireball Scoll, completing part 8
This commit is contained in:
parent
621d4780e8
commit
a1e6125c34
@ -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
|
||||||
|
@ -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),
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user