-
Notifications
You must be signed in to change notification settings - Fork 0
/
minion.py
136 lines (117 loc) · 4.8 KB
/
minion.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
from entity import Entity
from entity import BigEntity
import libtcodpy as libtcod
import effect
import tactic
from collections import defaultdict
class Minion(Entity):
def __init__(self, battleground, side, x=-1, y=-1, name="minion", char='m', color=libtcod.white):
super(Minion, self).__init__(battleground, side, x, y, char, color)
self.name = name
self.max_hp = 30
self.hp = 30
self.armor = defaultdict(lambda: 0)
self.power = 5
self.tactic = tactic.null
self.attack_effect = effect.TempEffect(self.bg, char='/' if side else '\\')
def can_be_attacked(self):
return True
def clone(self, x, y):
if self.bg.is_inside(x, y) and self.bg.tiles[(x, y)].entity is None and self.bg.tiles[(x, y)].is_passable(self):
return self.__class__(self.bg, self.side, x, y, self.name, self.char, self.original_color)
return None
def die(self):
super(Minion, self).die()
if self in self.bg.minions:
self.bg.generals[self.side].minions_alive -= 1
def enemy_reachable(self, diagonals=False):
# Order: forward, backward, up, down, then diagonals
order = [(1, 0), (-1, 0), (0, -1), (0, 1)]
if diagonals:
order.extend([(1, -1), (1, 1), (-1, -1), (-1, 1)])
for (i, j) in order:
enemy = self.bg.tiles[(self.x + (-i if self.side else i), self.y + j)].entity
if enemy and not self.is_ally(enemy) and enemy.can_be_attacked():
return enemy
return None
def follow_tactic(self):
self.tactic(self)
def get_attacked(self, enemy, power=None, attack_effect=None, attack_type=None):
if not power:
power = enemy.power
if not attack_effect:
attack_effect = enemy.attack_effect
if not attack_type:
attack_type = enemy.attack_type
self.hp -= max(0, power - self.armor[attack_type])
if attack_effect:
attack_effect.clone(self.x, self.y)
if self.hp > 0:
self.update_color()
else:
self.hp = 0
self.die()
enemy.register_kill(self)
def get_healed(self, amount):
self.hp += amount
if self.hp > self.max_hp: self.hp = self.max_hp
self.update_color()
def try_attack(self):
enemy = self.enemy_reachable()
if enemy:
enemy.get_attacked(self)
return enemy != None
def update(self):
if not self.alive: return
for s in self.statuses:
s.update()
if self.next_action <= 0:
self.reset_action()
if not self.try_attack():
self.follow_tactic()
else: self.next_action -= 1
def update_color(self):
# We change the color to indicate that the minion is wounded
# More red -> closer to death
c = int(255*(float(self.hp)/self.max_hp))
self.color = libtcod.Color(255, c, c)
class BigMinion(BigEntity, Minion):
def __init__(self, battleground, side, x=-1, y=-1, name="Giant", chars=['G']*4, colors=[libtcod.white]*4):
BigEntity.__init__(self, battleground, side, x, y, chars, colors)
Minion.__init__(self, battleground, side, x, y, name, colors[0])
self.max_hp *= self.length
self.hp = self.max_hp
def clone(self, x, y):
for (pos_x, pos_y) in [(x+i, y+j) for i in range (0, self.length) for j in range (0, self.length)]:
if not self.bg.is_inside(pos_x, pos_y) or self.bg.tiles[(pos_x, pos_y)].entity is not None or not self.bg.tiles[(x, y)].is_passable(self):
return None
entity = self.__class__(self.bg, self.side, x, y, self.name, self.color)
entity.update_body()
return entity
def enemy_reachable(self):
# Order: forward, backward, up, down
for (dx, dy) in [(1 if self.side == 0 else -1, 0), (1 if self.side == 0 else -1, 0), (0, 1), (0, -1)]:
for (x,y) in [(self.x+dx+x,self.y+dy+y) for x in range (0, self.length) for y in range (0, self.length)]:
enemy = self.bg.tiles[(x, y)].entity
if enemy is not None and not self.is_ally(enemy) and enemy.can_be_attacked():
return enemy
return None
class RangedMinion(Minion):
def __init__(self, battleground, side, x=-1, y=-1, name="archer", color=libtcod.white, attack_effects = ['>', '<']):
super(RangedMinion, self).__init__(battleground, side, x, y, name)
self.max_hp = 10
self.hp = 10
self.power = 1
self.ranged_power = 4
self.attack_effects = attack_effects
self.default_next_action = 10
self.reset_action()
def clone(self, x, y):
if super(RangedMinion, self).clone(x, y) == None: return None
return self.__class__(self.bg, self.side, x, y, self.name, self.original_color, self.attack_effects)
def follow_tactic(self):
if self.tactic is None: return
next_x = self.x+1 if self.side == 0 else self.x-1
if self.tactic == tactic.stop and self.bg.tiles[(next_x, self.y)].entity == None:
self.bg.effects.append(effect.Arrow(self.bg, self.side, next_x, self.y, self.ranged_power, self.attack_effects))
else: super(RangedMinion, self).follow_tactic()