Module npc_guard
[hide private]
[frames] | no frames]

Source Code for Module npc_guard

  1  #!/usr/bin/python3 
  2  # pylint: disable=invalid-name; "Npc_guard" would be an abomination 
  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   
10 -class NPC_guard(GameActor):
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 # default attributes ... easily changed after instantiation 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) # slashes are harder to dodge 30 self.set("PROTECTION", 2) # by default, cheap armor 31 self.set("reinforcements", 0) # by default, alone 32 33 self.weapon = GameObject("sword") 34 self.weapon.set("ACTIONS", "ATTACK.slash") 35 self.weapon.set("DAMAGE.slash", "D6") 36 37 # sub-class combat attributes 38 self.help_arrived = False 39 self.target = None
40
41 - def accept_action(self, action, actor, context):
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 # remember where this is happening 56 self.context = context 57 58 # start with standard GameActor responses 59 (hit, desc) = super(NPC_guard, self).accept_action(action, 60 actor, context) 61 62 # figure out the action verb and sub-type 63 if '.' in action.verb: 64 base_verb = action.verb.split('.')[0] 65 else: 66 base_verb = action.verb 67 68 # if I have been attacked, and am not dead 69 if base_verb == "ATTACK" and \ 70 self.get("LIFE") > 0: 71 # counter attack when our turn comes 72 self.target = actor 73 74 # see if we can call for help 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 # and return our (perhaps updated) result 87 return (hit, desc)
88
89 - def take_turn(self):
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 # UNIT TESTING
108 -class NoGoodNick(GameActor):
109 """ 110 A NoGoodNick is an actor who will attack a guard and report when 111 he is (counter-) attacked, and by whom 112 """
113 - def __init__(self, name):
114 """ 115 @param name: (string) name of this actor 116 """ 117 118 # create a bad-guy brawler 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
127 - def accept_action(self, action, actor, context):
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
139 -def test_target():
140 """ 141 create a GameActor who attacks me, and confirm that I return the attack 142 """ 143 # create a guard and a thug in an arena 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 # thug attacks the guard 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 # confirm guard knows who attacked him 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 # confirm guard's next turn counter-attacks his attacker 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
177 -def test_reinforcements():
178 """ 179 create a GameActor who attacks me, and confirm that I call for 180 reinforcements, who will attack my attacker 181 """ 182 # create a guard (who likes help) and a thug in an arena 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 # thug attacks the guard 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 # confirm there is now (another) NPC in the context 201 tried += 1 202 npcs = cxt.get_npcs() 203 assert len(npcs) == 2, "Reinforcement not added to context" 204 passed += 1 205 206 # confirm there is someone other than me in the context 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 # confirm helper knows who the enemy is 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 # confirm helper attacks the thug on his next turn 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
236 -def main():
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