44import math
55from typing import Optional , Tuple , Type , TypeVar , TYPE_CHECKING , Union
66
7+ from engine import Engine
78from render_order import RenderOrder
89
910if TYPE_CHECKING :
1516 from components .inventory import Inventory
1617 from components .level import Level
1718 from game_map import GameMap
19+ from input_handlers import EventHandler
20+
1821
1922T = TypeVar ("T" , bound = "Entity" )
2023
@@ -48,6 +51,7 @@ def __init__(
4851 self .blocks_movement = blocks_movement
4952 self .render_order = render_order
5053 self .inspect_message = inspect_message
54+ self .is_swarm = False
5155 if parent :
5256 # If parent isn't provided now then it will be set later.
5357 self .parent = parent
@@ -57,11 +61,12 @@ def __init__(
5761 def gamemap (self ) -> GameMap :
5862 return self .parent .gamemap
5963
60- def spawn (self : T , gamemap : GameMap , x : int , y : int ) -> T :
64+ def spawn (self : T , gamemap : GameMap , x : int , y : int , is_swarm : Optional [ bool ] = False ) -> T :
6165 """Spawn a copy of this instance at the given location."""
6266 clone = copy .deepcopy (self )
6367 clone .x = x
6468 clone .y = y
69+ clone .is_swarm = is_swarm
6570 clone .parent = gamemap
6671 gamemap .entities .add (clone )
6772 return clone
@@ -73,7 +78,7 @@ def distance(self, x: int, y: int) -> float:
7378 return math .sqrt ((x - self .x ) ** 2 + (y - self .y ) ** 2 )
7479
7580
76- def place (self , x : int , y : int , gamemap : Optional [GameMap ] = None ) -> None :
81+ def place (self , x : int , y : int , gamemap : Optional [GameMap ] = None , is_swarm : Optional [ bool ] = False ) -> None :
7782 """Place this entity at a new location. Handles moving across GameMaps."""
7883 self .x = x
7984 self .y = y
@@ -82,7 +87,9 @@ def place(self, x: int, y: int, gamemap: Optional[GameMap] = None) -> None:
8287 if self .parent is self .gamemap :
8388 self .gamemap .entities .remove (self )
8489 self .parent = gamemap
90+ self .is_swarm = is_swarm # If this is a swarm, then it will not give XP when it dies.
8591 gamemap .entities .add (self )
92+ self .is_swarm = False
8693
8794 def move (self , dx : int , dy : int ) -> None :
8895 """
@@ -142,6 +149,49 @@ def is_alive(self) -> bool:
142149 """Returns True as long as this actor can perform actions."""
143150 return bool (self .ai )
144151
152+ class NPC (Entity ):
153+ """
154+ A NPC (Non-player character) is used for freindly npcs the player can interact with. Such as merchants, quest givers, etc.
155+ """
156+
157+ def __init__ (
158+ self ,
159+ * ,
160+ x : int = 0 ,
161+ y : int = 0 ,
162+ char : str = "?" ,
163+ color : Tuple [int , int , int ] = (255 , 255 , 255 ),
164+ name : str = "<Unnamed>" ,
165+ inspect_message : Optional [str ] = "I don't know what this thing is." ,
166+ interact_input_handler_cls : Type [EventHandler ]
167+ ):
168+ super ().__init__ (
169+ x = x ,
170+ y = y ,
171+ char = char ,
172+ color = color ,
173+ name = name ,
174+ blocks_movement = True ,
175+ render_order = RenderOrder .ACTOR ,
176+ inspect_message = inspect_message ,
177+ )
178+ self .is_npc = True
179+ self .input_handler_class = interact_input_handler_cls
180+
181+ def init_handler (self , engine : Engine ) -> None :
182+ self .input_handler = self .input_handler_class (engine )
183+
184+ def interact (self ) -> EventHandler :
185+ """
186+ Interact with this NPC.
187+ """
188+ self .parent .engine .message_log .add_message (f"You interact with the { self .name } ." )
189+
190+ return self .input_handler
191+
192+
193+
194+
145195class Item (Entity ):
146196 """
147197 An item that can be picked up and used, uuses item especific components.
@@ -157,6 +207,7 @@ def __init__(
157207 inspect_message : Optional [str ] = "I don't know what this thing is." ,
158208 consumable : Optional [Consumable ] = None ,
159209 equippable : Optional [Equippable ] = None ,
210+ value : int = 0 ,
160211 ):
161212 super ().__init__ (
162213 x = x ,
@@ -169,6 +220,7 @@ def __init__(
169220 inspect_message = inspect_message ,
170221 )
171222
223+ self .value = value
172224 self .consumable = consumable
173225 if self .consumable :
174226 self .consumable .parent = self
0 commit comments