-
Notifications
You must be signed in to change notification settings - Fork 3
/
components.py
165 lines (136 loc) · 4.38 KB
/
components.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
"""
Simple entity system: any renderable Object can have
a number of Components attached.
"""
import math
import algebra
class Object:
"""
This is a generic object: the player, a monster, an item, the stairs...
It's always represented by a character on screen.
"""
def __init__(self, pos, char, name, color,
blocks=False, always_visible=False,
fighter=None, ai=None, item=None, equipment=None):
self.pos = pos
self.char = char
self.name = name
self.color = color
self.blocks = blocks
self.always_visible = always_visible
self.fighter = fighter
self._ensure_ownership(fighter)
self.ai = ai
self._ensure_ownership(ai)
self.item = item
self._ensure_ownership(item)
self.equipment = equipment
self._ensure_ownership(equipment)
@property
def x(self):
return self.pos.x
@property
def y(self):
return self.pos.y
def _ensure_ownership(self, component):
if (component):
component.set_owner(self)
def distance_to(self, other):
"""
Return the distance to another object.
"""
dx = other.x - self.x
dy = other.y - self.y
return math.sqrt(dx ** 2 + dy ** 2)
def distance(self, x, y):
"""
Return the distance to some coordinates.
"""
return math.sqrt((x - self.x) ** 2 + (y - self.y) ** 2)
def distance(self, pos):
"""
Return the distance to some coordinates.
"""
return math.sqrt((pos.x - self.x) ** 2 + (pos.y - self.y) ** 2)
class Component:
"""
Base class for components to minimize boilerplate.
"""
def set_owner(self, entity):
self.owner = entity
class Fighter(Component):
"""
Combat-related properties and methods (monster, player, NPC).
"""
def __init__(self, hp, defense, power, xp, death_function=None):
self.base_max_hp = hp
self.hp = hp
self.base_defense = defense
self.base_power = power
self.xp = xp
self.death_function = death_function
@property
def power(self):
bonus = sum(equipment.power_bonus for equipment
in _get_all_equipped(self.owner))
return self.base_power + bonus
@property
def defense(self):
bonus = sum(equipment.defense_bonus for equipment
in _get_all_equipped(self.owner))
return self.base_defense + bonus
@property
def max_hp(self):
bonus = sum(equipment.max_hp_bonus for equipment
in _get_all_equipped(self.owner))
return self.base_max_hp + bonus
class Item(Component):
"""
An item that can be picked up and used.
"""
def __init__(self, description=None, count=1, use_function=None):
self.description = description
self.use_function = use_function
self.count = count
def can_combine(self, other):
"""
Returns true if other can stack with self.
Terribly simple for now.
"""
return other.item and other.name == self.owner.name
class Equipment(Component):
"""
An object that can be equipped, yielding bonuses.
Requires an Item component.
"""
def __init__(self, slot, power_bonus=0, defense_bonus=0, max_hp_bonus=0):
self.power_bonus = power_bonus
self.defense_bonus = defense_bonus
self.max_hp_bonus = max_hp_bonus
self.slot = slot
self.is_equipped = False
def set_owner(self, entity):
Component.set_owner(self, entity)
# There must be an Item component for the Equipment
# component to work properly.
if entity.item is None:
entity.item = Item()
entity.item.set_owner(entity)
class AI(Component):
def __init__(self, take_turn, metadata=None):
self._turn_function = take_turn
self._metadata = metadata
def take_turn(self, player):
self._turn_function(self.owner, player, self._metadata)
def _get_all_equipped(obj):
"""
Returns a list of all equipped items.
"""
if hasattr(obj, 'inventory'):
equipped_list = []
for item in obj.inventory:
if item.equipment and item.equipment.is_equipped:
equipped_list.append(item.equipment)
return equipped_list
else:
return []