1
2
3 """ This module implements the NPC_guard class """
4 from random import randint
5 from gameobject import GameObject
6 from gameactor import GameActor
7 from gamecontext import GameContext
8
9
11 """
12 A guard is a low-level NPC fighter who will quickly
13 engage and can call for reinforcements.
14 """
15 - def __init__(self, name="guard", descr=None):
16 """
17 create a new GameObject
18 @param name: display name of this object
19 @param descr: human description of this object
20 """
21 super(NPC_guard, self).__init__(name, descr)
22 self.context = None
23
24
25 self.set("HP", 16)
26 self.set("LIFE", 16)
27 self.set("ACCURACY", 10)
28 self.set("EVASION", 40)
29 self.set("EVASION.slash", 20)
30 self.set("PROTECTION", 2)
31 self.set("reinforcements", 0)
32
33 self.weapon = GameObject("sword")
34 self.weapon.set("ACTIONS", "ATTACK.slash")
35 self.weapon.set("DAMAGE.slash", "D6")
36
37
38 self.help_arrived = False
39 self.target = None
40
42 """
43 receive and process the effects of an action
44
45 @param action: GameAction being performed
46 @param actor: GameActor) initiating the action
47 @param context: GameContext in which action is being taken
48 @return: (boolean success, string description of the effect)
49
50 The only special things about a guard ar that, if attacked
51 (1) he counter-attacks
52 (2) he can call for reinforcements.
53
54 """
55
56 self.context = context
57
58
59 (hit, desc) = super(NPC_guard, self).accept_action(action,
60 actor, context)
61
62
63 if '.' in action.verb:
64 base_verb = action.verb.split('.')[0]
65 else:
66 base_verb = action.verb
67
68
69 if base_verb == "ATTACK" and \
70 self.get("LIFE") > 0:
71
72 self.target = actor
73
74
75 if self.get("reinforcements") > 0 and not self.help_arrived:
76 desc += "\n " + self.name + " calls for help"
77 roll = randint(1, 100)
78 if roll <= self.get("reinforcements"):
79 helper = NPC_guard("Guard #2", "test reinforcement")
80 helper.target = actor
81 desc += ", and " + helper.name + " arrives"
82 context.add_npc(helper)
83 helper.set_context(context)
84 self.help_arrived = True
85
86
87 return (hit, desc)
88
90 """
91 Take action when your turn comes.
92 The only actions this test Guard can take are fighting back
93 """
94 if self.target is not None:
95 weapon = self.weapon
96 actions = weapon.possible_actions(self.target, self.context)
97 attack = actions[randint(0, len(actions)-1)]
98 (success, desc) = self.take_action(actions[0], self.target)
99 return (success,
100 "\n{} uses {} to {} {}, delivered={}\n {}"
101 .format(self.name, weapon.name, attack.verb,
102 self.target.name, attack.get("HIT_POINTS"),
103 desc))
104 return super(NPC_guard, self).take_turn()
105
106
107
109 """
110 A NoGoodNick is an actor who will attack a guard and report when
111 he is (counter-) attacked, and by whom
112 """
114 """
115 @param name: (string) name of this actor
116 """
117
118
119 super(NoGoodNick, self).__init__(name, "test aggressor")
120 self.set("HP", 16)
121 self.set("LIFE", 16)
122 self.set("ACCURACY", 10)
123 self.set("EVASION", 40)
124 self.set("DAMAGE", "D6")
125 self.set("ACTIONS", "ATTACK.BRAWL")
126
128 """
129 receive an attack and report who made it
130
131 @param action: GameAction being performed
132 @param actor: GameActor) initiating the action
133 @param context: GameContext in which action is being taken
134 @return: (boolean success, string description of the effect)
135 """
136 return (True, "{} counter-attacks {}".format(actor.name, self.name))
137
138
140 """
141 create a GameActor who attacks me, and confirm that I return the attack
142 """
143
144 cxt = GameContext("the arena")
145 good_guy = NPC_guard("guard #1")
146 bad_guy = NoGoodNick("thug #1")
147 assault = bad_guy.possible_actions(good_guy, cxt)[0]
148
149 tried = 0
150 passed = 0
151
152
153 tried += 1
154 print("{} {}s {} in {}".
155 format(bad_guy.name, assault.verb, good_guy.name, cxt.name))
156 (_, desc) = assault.act(bad_guy, good_guy, cxt)
157 print(desc)
158
159
160 assert good_guy.target is bad_guy, \
161 "after being attacked, {} does not target {}"\
162 .format(good_guy.name, bad_guy.name)
163 passed += 1
164
165
166 tried += 1
167 (_, desc) = good_guy.take_turn()
168 print(desc)
169 assert "guard #1 counter-attacks thug #1" in desc,\
170 "after being attacked, guard's turn is not counter-attack"
171 passed += 1
172
173 print()
174 return (tried, passed)
175
176
178 """
179 create a GameActor who attacks me, and confirm that I call for
180 reinforcements, who will attack my attacker
181 """
182
183 cxt = GameContext("the arena")
184 good_guy = NPC_guard("guard #1")
185 cxt.add_npc(good_guy)
186 good_guy.set("reinforcements", 100)
187
188 bad_guy = NoGoodNick("thug #1")
189 assault = bad_guy.possible_actions(good_guy, cxt)[0]
190
191 tried = 0
192 passed = 0
193
194
195 print("{} {}s {} in {}".
196 format(bad_guy.name, assault.verb, good_guy.name, cxt.name))
197 (_, desc) = assault.act(bad_guy, good_guy, cxt)
198 print(desc)
199
200
201 tried += 1
202 npcs = cxt.get_npcs()
203 assert len(npcs) == 2, "Reinforcement not added to context"
204 passed += 1
205
206
207 tried += 1
208 helper = None
209 for npc in npcs:
210 if npc.name != good_guy.name:
211 helper = npc
212
213 assert helper is not None, \
214 "Nobody but {} in context".format(good_guy.name)
215 passed += 1
216
217
218 tried += 1
219 assert helper.target is bad_guy, \
220 "after coming to assist, {} does not target {}"\
221 .format(helper.name, bad_guy.name)
222 passed += 1
223
224
225 tried += 1
226 (_, desc) = helper.take_turn()
227 print(desc)
228 assert "{} counter-attacks thug #1".format(helper.name) in desc,\
229 "after being attacked, guard's turn is not counter-attack"
230 passed += 1
231
232 print()
233 return (tried, passed)
234
235
237 """
238 Run all unit-test cases and print out summary of results
239 """
240 (t_1, p_1) = test_target()
241 (t_2, p_2) = test_reinforcements()
242 tried = t_1 + t_2
243 passed = p_1 + p_2
244 if tried == passed:
245 print("Passed all {} NPC_guard tests".format(passed))
246 else:
247 print("FAILED {}/{} GameNPC_guard tests".format(tried-passed, tried))
248
249
250 if __name__ == "__main__":
251 main()
252