From 5b5f49bf6b87da85fb37e0b041ab1c0267a969e5 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Thu, 13 Jan 2022 14:56:38 -0500 Subject: [PATCH] Add lighting scroll --- color.py | 3 +++ components/consumable.py | 28 ++++++++++++++++++++++++++++ entity.py | 7 +++++++ entity_factories.py | 15 +++++++++++---- procgen.py | 7 ++++++- 5 files changed, 55 insertions(+), 5 deletions(-) diff --git a/color.py b/color.py index 44b4981..4dc7474 100644 --- a/color.py +++ b/color.py @@ -1,8 +1,11 @@ white = (0xFF, 0xFF, 0xFF) black = (0x0, 0x0, 0x0) +red = (0xFF, 0x0, 0x0) player_atk = (0xE0, 0xE0, 0xE0) enemy_atk = (0xFF, 0xC0, 0xC0) +needs_target = (0x3F, 0xFF, 0xFF) +status_effect_applied = (0x3F, 0xFF, 0x3F) player_die = (0xFF, 0x30, 0x30) enemy_die = (0xFF, 0xA0, 0x30) diff --git a/components/consumable.py b/components/consumable.py index af161a6..9128bd7 100644 --- a/components/consumable.py +++ b/components/consumable.py @@ -50,3 +50,31 @@ class HealingConsumable(Consumable): self.consume() else: raise Impossible(f"Your health is already full.") + + +class LightningDamageConsumable(Consumable): + def __init__(self, damage: int, maximum_range: int): + self.damage = damage + self.maximum_range = maximum_range + + def activate(self, action: actions.ItemAction) -> None: + consumer = action.entity + target = None + closest_distance = self.maximum_range + 1.0 + + for actor in self.engine.game_map.actors: + if actor is not consumer and self.parent.gamemap.visible[actor.x, actor.y]: + distance = consumer.distance(actor.x, actor.y) + + if distance < closest_distance: + target = actor + closest_distance = distance + + if target: + self.engine.message_log.add_message( + f"A lightning bolt stikes the {target.name} with a loud thunder, for {self.damage} damage!" + ) + target.fighter.take_damage(self.damage) + self.consume() + else: + raise Impossible("No enemy is close enough to strike.") diff --git a/entity.py b/entity.py index b88df62..7122150 100644 --- a/entity.py +++ b/entity.py @@ -1,6 +1,7 @@ from __future__ import annotations import copy +import math from typing import Optional, Tuple, Type, TypeVar, TYPE_CHECKING, Union from render_order import RenderOrder @@ -70,6 +71,12 @@ class Entity: self.parent = gamemap gamemap.entities.add(self) + def distance(self, x: int, y: int) -> float: + """ + Return the distance between the current entity and the given (x,y) coordinate. + """ + return math.sqrt((x - self.x) ** 2 + (y - self.y) ** 2) + def move(self, dx: int, dy: int): # Move the entity by a given amount self.x += dx diff --git a/entity_factories.py b/entity_factories.py index ca8f24f..4297b8f 100644 --- a/entity_factories.py +++ b/entity_factories.py @@ -1,5 +1,5 @@ from components.ai import HostileEnemy -from components.consumable import HealingConsumable +from components import consumable from components.fighter import Fighter from components.inventory import Inventory from entity import Actor, Item @@ -19,7 +19,7 @@ orc = Actor( name="Orc", ai_cls=HostileEnemy, fighter=Fighter(hp=10, defense=0, power=3), - inventory=Inventory(capacity=0) + inventory=Inventory(capacity=0), ) troll = Actor( char="T", @@ -27,12 +27,19 @@ troll = Actor( name="Troll", ai_cls=HostileEnemy, fighter=Fighter(hp=16, defense=1, power=4), - inventory=Inventory(capacity=0) + inventory=Inventory(capacity=0), ) health_potion = Item( char="!", color=(127, 0, 255), name="Health Potion", - consumable=HealingConsumable(amount=4) + consumable=consumable.HealingConsumable(amount=4), +) + +lightning_scroll = Item( + char="~", + color=(255, 255, 0), + name="Lightning Scroll", + consumable=consumable.LightningDamageConsumable(damage=20, maximum_range=5), ) diff --git a/procgen.py b/procgen.py index ffeddb2..abb49ef 100644 --- a/procgen.py +++ b/procgen.py @@ -66,7 +66,12 @@ def place_entities( y = random.randint(room.y1 + 1, room.y2 - 1) if not any(entity.x == x and entity.y == y for entity in dungeon.entities): - entity_factories.health_potion.spawn(dungeon, x, y) + item_chance = random.random() + + if item_chance < 0.7: + entity_factories.health_potion.spawn(dungeon, x, y) + else: + entity_factories.lightning_scroll.spawn(dungeon, x, y) def tunnel_between(start: Tuple[int, int], end: Tuple[int, int]) -> Iterator[Tuple[int, int]]: