def probableRangedAttack(self): """ Return an action for a ranged attack on a target if such an attack is possible. Otherwise, return None. """ if "two_square_thrower" in self.tags: if self.currentLevel.player in self.fov \ and coordinates.minimumPath(self.coords, self.currentLevel.player.coords) in range(1, 4): possible_directions = ((2, 0), (2, 2), (0, 2), (-2, 2), (-2, 0), (-2, -2), (0, -2), (2, -2)) possible_targets = [ coordinates.add(self.coords, i) for i in possible_directions if self.currentLevel.isEmpty( coordinates.add(self.coords, i)) ] visible_targets = [ coords for coords in possible_targets if coords in self.fov ] close_targets = [ coords for coords in visible_targets if (coordinates.minimumPath( coords, self.currentLevel.player.coords) <= 1) ] actual_targets = [ coords for coords in close_targets if coords not in self.currentLevel.dudeLayer ] if len(actual_targets) == 0: return None final_target = rng.choice(actual_targets) return action.ThrowGrenade(self, final_target) else: return None elif "straight_shooter" in self.tags: direction = coordinates.get_cardinal_direction( self.coords, self.currentLevel.player.coords) dist = coordinates.minimumPath(self.coords, self.currentLevel.player.coords) if self.currentLevel.player in self.fov \ and direction is not None \ and dist < 12: if self.spec == "ARROW": return action.FireArrow(self, direction, 12) elif self.spec == "POUNCE": return action.Pounce(self, direction, 12) else: assert False return None else: return None else: return None
def do(self): if self.prev_summons < len(self.SUMMONS): self.level_.messages.append(self.message) enemy_list = self.SUMMONS[self.prev_summons] for (name, coords) in enemy_list: real_coords = coordinates.add(coords, self.CENTER) mon = self.level_.createMonster(name, real_coords)
def do(self): cur_lev = self.source.currentLevel next_loc = self.source.coords # Essentially a for loop, for i in range(self.distance). i = 0 while True: if i >= self.distance: cur_lev.messages.append("%s pounced, but caught only air." % self.source.getName()) break i += 1 next_loc = coordinates.add(self.source.coords, self.direction) display.refresh_screen() if not cur_lev.isEmpty(next_loc): cur_lev.messages.append("%s pounced at the wall." % self.source.getName()) break elif next_loc in cur_lev.dudeLayer: # The pouncer hit a dude. target = cur_lev.dudeLayer[next_loc] # Bounce off: behind the dude if possible, in front otherwise. behind = coordinates.add(next_loc, self.direction) in_front = coordinates.subtract(next_loc, self.direction) if (cur_lev.isEmpty(behind) and behind not in cur_lev.dudeLayer): cur_lev.moveDude(self.source, behind) # The pouncer should already be in front of the target, so if it is not going # through them, no motion is necessary. damage_dealt = damage(self.source.attack, target.defense, self.source.char_level, target.char_level) cur_lev.messages.append("%s pounced on %s! (%d)" % (self.source.getName(), target.getName(), damage_dealt)) target.cur_HP -= damage_dealt target.checkDeath() break else: cur_lev.moveDude(self.source, next_loc) display.refresh_screen() return self.source.speed
def getAction(self, dude_): if dude_.canMove(coordinates.add(dude_.coords, self.direction)) \ and len(dude_.fov.dudes) == 0: return action.Move(dude_, self.direction) else: self.time = -5 return None
def do_special_melee(attack_type, source, target): """ Have a Dude perform a special melee attack. attack_type - a string representing the type of special attack. source - the Dude attacking. target - the Dude being attacked. """ if attack_type == "CRITICAL": damage_dealt = CRIT_MULTIPLIER * \ damage(source.attack, target.defense, source.char_level, target.char_level) source.currentLevel.messages.append( "%(SOURCE_NAME)s runs %(TARGET_NAME)s all the way through! (%(DAMAGE)d)" % {"SOURCE_NAME": source.getName(), "DAMAGE": damage_dealt, "TARGET_NAME": target.getName()}) target.cur_HP -= damage_dealt target.checkDeath() elif attack_type == "KNOCK": damage_dealt = KNOCK_DAMAGE direction = coordinates.subtract(target.coords, source.coords) source.currentLevel.messages.append( "%(SOURCE_NAME)s delivers a wicked punch to %(TARGET_NAME)s! (%(DAMAGE)d)" % {"SOURCE_NAME": source.getName(), "DAMAGE": damage_dealt, "TARGET_NAME": target.getName()}) for i in range(KNOCK_DISTANCE): display.refresh_screen() destination = coordinates.add(target.coords, direction) if target.canMove(destination): target.currentLevel.moveDude(target, destination) else: break display.refresh_screen() target.cur_HP -= damage_dealt target.checkDeath() elif attack_type == "EXPLODE": explode_action = Explode(source.currentLevel, source.coords, 10) source.currentLevel.messages.append( "%(SOURCE_NAME)s explodes!" % {"SOURCE_NAME": source.getName()}) explode_action.do() elif attack_type == "STICK": damage_dealt = damage(source.attack, target.defense, source.char_level, target.char_level) / 5 source.currentLevel.messages.append( "%(SOURCE_NAME)s spins a web around %(TARGET_NAME)s! (%(DAMAGE)d)" % {"SOURCE_NAME": source.getName(), "DAMAGE": damage_dealt, "TARGET_NAME": target.getName()}) target.giveCondition(cond.Stuck(8)) target.cur_HP -= damage_dealt target.checkDeath() else: raise exc.InvalidDataWarning("%s special ability used by %s on %s." % (attack_type, str(source), str(target)))
def do(self): """ Move the source of the action in the direction specified. Raise a ValueError if such a move is illegal. act - the action to be performed. Returns True if the move can be performed, and returns False if it cannot. """ destination_coords = coordinates.add(self.source.coords, self.coords) if self.source.canMove(destination_coords): self.source.currentLevel.moveDude(self.source, destination_coords) return self.source.speed else: assert False return 0
def copy_array_subset(src_nw_corner, dst_nw_corner, block_dims, src_array, dst_array): """ This function differs only from copy_array_subset_lenient in that it raises exceptions whenever the coordinates given refer to squares not actually in the arrays provided. """ exc.check_in_array(src_nw_corner, src_array.shape) exc.check_in_array(dst_nw_corner, dst_array.shape) exc.check_in_array(coordinates.add(coordinates.add(src_nw_corner, block_dims), (-1, -1)), src_array.shape) exc.check_in_array(coordinates.add(coordinates.add(dst_nw_corner, block_dims), (-1, -1)), dst_array.shape) for x in range(block_dims[0]): for y in range(block_dims[1]): dst_array[coordinates.add(dst_nw_corner, (x, y))] = src_array[coordinates.add(src_nw_corner, (x, y))] return
def do(self): current_location = self.source.coords self.source.currentLevel.addSolidEffect(current_location, ARROW_GLYPH) self.source.currentLevel.makeNoise( self.message % {"SOURCE_NAME": self.source.getName()}, self.source.coords) i = 0 while True: i += 1 display.refresh_screen() self.source.currentLevel.removeSolidEffect(current_location, ARROW_GLYPH) current_location = coordinates.add(current_location, self.direction) self.source.currentLevel.addSolidEffect(current_location, ARROW_GLYPH) if not self.source.currentLevel.isEmpty(current_location): break # If the arrow runs into a wall, just stop. elif current_location in self.source.currentLevel.dudeLayer: # The arrow hit a dude! target = self.source.currentLevel.dudeLayer[current_location] damage_dealt = damage(self.source.attack, target.defense, self.source.char_level, target.char_level) self.source.currentLevel.makeNoise( "The arrow hit %s. (%d)" % (target.getName(), damage_dealt), self.source.coords) display.refresh_screen() target.cur_HP -= damage_dealt target.checkDeath() self.source.currentLevel.removeSolidEffect(current_location, ARROW_GLYPH) break else: if i >= 12: self.source.currentLevel.removeSolidEffect(current_location, ARROW_GLYPH) display.refresh_screen() break return self.source.speed
def randomDungeon(): """ Gets a random dungeon, using a very simple room/corridor model. The room/corridor model used is similar to that of Rogue; the map is divided into nine sectors, each of which is randomly called a room, a corridor, or empty. Once this is done, rooms and corridors are connected to adjacent rooms and corridors. This is coded terribly because it will be replaced someday. """ map_dimensions = (60, 60) map_nwcorner = (10, 10) sector_size = (12, 12) sector_nwcorners = {} for x in range(0, 3): for y in range(0, 3): sector_nwcorners[(x, y)] = ( map_nwcorner[0] + sector_size[0] * x, map_nwcorner[1] + sector_size[1] * y ) sector_types = {} for x in range(0, 3): for y in range(0, 3): percent = rng.randInt(1, 100) if percent <= 60: sector_types[(x, y)] = 1 # it's a room! elif percent <= 75: sector_types[(x, y)] = 2 # it's a corridor! else: sector_types[(x, y)] = 0 # it's empty! room_nwcoords = {} room_secoords = {} for sector_coords in sector_types.keys(): if sector_types[sector_coords] == 1: room_created = False sector_nw = sector_nwcorners[sector_coords] sector_se = (sector_nw[0] + sector_size[0] - 1, sector_nw[1] + sector_size[1] - 1) while not room_created: room_nw = (rng.randInt(sector_nw[0], sector_se[0]), rng.randInt(sector_nw[1], sector_se[1])) room_se = (room_nw[0] + rng.randInt(3, 8), room_nw[1] + rng.randInt(3, 8)) # check validity of room dimensions if room_se[0] <= sector_se[0] and room_se[1] <= sector_se[1]: room_nwcoords[sector_coords] = room_nw room_secoords[sector_coords] = room_se room_created = True elif sector_types[sector_coords] == 2: # A corridor is currently implemented as just a 1-space room. corridor_coords = (rng.randInt(sector_nwcorners[sector_coords][0], sector_nwcorners[sector_coords][0] + sector_size[0] - 1,), rng.randInt(sector_nwcorners[sector_coords][1], sector_nwcorners[sector_coords][1] + sector_size[1] - 1,)) room_nwcoords[sector_coords] = corridor_coords room_secoords[sector_coords] = corridor_coords # Check whether everywhere is accessible; if not, do a redo. sector_is_accessible = {} for x in range(3): for y in range(3): sector_is_accessible[(x, y)] = False for coord in ((0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)): if True not in sector_is_accessible.values() and sector_types[coord] != 0: sector_is_accessible[coord] = True if sector_is_accessible[coord] == True and sector_types[coord] != 0: for coord_adjustment in ((1, 0), (0, 1), (-1, 0), (0, -1)): adjacent_coord = coordinates.add(coord, coord_adjustment) if (adjacent_coord[0] >= 0 and adjacent_coord[0] < 3 and adjacent_coord[1] >= 0 and adjacent_coord[1] < 3): sector_is_accessible[adjacent_coord] = True for accessible in sector_is_accessible.items(): if sector_types[accessible[0]] != 0 and not accessible[1]: # Oops. Give up and try again. return randomDungeon() entrance_sector = rng.choice([coords for coords in sector_types.keys() if sector_types[coords] == 1]) exit_sector = rng.choice([coords for coords in sector_types.keys() if sector_types[coords] == 1]) entrance_coords = rng.randomPointInRect(room_nwcoords[entrance_sector], room_secoords[entrance_sector]) exit_coords = rng.randomPointInRect(room_nwcoords[exit_sector], room_secoords[exit_sector]) ret_dungeon = level.empty_dungeon(map_dimensions) for coord in ((0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)): if sector_types[coord] != 0: for x in range(room_nwcoords[coord][0], room_secoords[coord][0] + 1): for y in range(room_nwcoords[coord][1], room_secoords[coord][1] + 1): if sector_types[coord] == 1: ret_dungeon[(x, y)] = level.ROOM_INTERIOR_GLYPH else: ret_dungeon[(x, y)] = level.CORRIDOR_GLYPH for coord_adjustment in ((1, 0), (0, 1)): adjacent_coord = coordinates.add(coord, coord_adjustment) if (adjacent_coord[0] < 3 and adjacent_coord[1] < 3 and sector_types[adjacent_coord] != 0): make_corridor(ret_dungeon, rng.randomPointInRect(room_nwcoords[coord], room_secoords[coord]), rng.randomPointInRect(room_nwcoords[adjacent_coord], room_secoords[adjacent_coord])) ret_dungeon[entrance_coords] = level.UPSTAIRS_GLYPH ret_dungeon[exit_coords] = level.DOWNSTAIRS_GLYPH return ret_dungeon
def randomDungeon(): """ Gets a random dungeon, using a very simple room/corridor model. The room/corridor model used is similar to that of Rogue; the map is divided into nine sectors, each of which is randomly called a room, a corridor, or empty. Once this is done, rooms and corridors are connected to adjacent rooms and corridors. This is coded terribly because it will be replaced someday. """ map_dimensions = (MAX_SIZE_X, MAX_SIZE_Y) map_nwcorner = (NW_CORNER_X, NW_CORNER_Y) sector_size = (SECTOR_SIZE_X, SECTOR_SIZE_Y) sector_list = [(x, y) for x in range(NUM_SECTORS_X) for y in range(NUM_SECTORS_Y)] sector_nwcorners = {} for x in range(NUM_SECTORS_X): for y in range(NUM_SECTORS_Y): sector_nwcorners[(x, y)] = ( map_nwcorner[0] + sector_size[0] * x, map_nwcorner[1] + sector_size[1] * y ) sector_types = {} for x in range(NUM_SECTORS_X): for y in range(NUM_SECTORS_Y): percent = rng.randInt(1, 100) if percent <= 25: sector_types[(x, y)] = st.ROOM elif percent <= 60: sector_types[(x, y)] = st.DOUBLE_ROOM elif percent <= 75: sector_types[(x, y)] = st.CORRIDOR else: sector_types[(x, y)] = st.EMPTY room_nwcoords = {} room_secoords = {} for sector_coords in sector_types.keys(): sector_nw = sector_nwcorners[sector_coords] sector_se = (sector_nw[0] + sector_size[0] - 1, sector_nw[1] + sector_size[1] - 1) if sector_types[sector_coords] in (st.ROOM, st.DOUBLE_ROOM): (room_nwcoords[sector_coords], room_secoords[sector_coords]) \ = choose_room_corners(sector_nw, sector_se) elif sector_types[sector_coords] == st.CORRIDOR: # A corridor is currently implemented as just a 1-space room. corridor_coords = (rng.randInt(sector_nw[0], sector_se[0]), rng.randInt(sector_nw[1], sector_se[1])) room_nwcoords[sector_coords] = corridor_coords room_secoords[sector_coords] = corridor_coords # Check whether everywhere is accessible; if not, do a redo. sector_is_accessible = {} for x in range(NUM_SECTORS_X): for y in range(NUM_SECTORS_Y): sector_is_accessible[(x, y)] = False for coord in sector_list: if True not in sector_is_accessible.values() \ and sector_types[coord] != 0: sector_is_accessible[coord] = True if sector_is_accessible[coord] == True \ and sector_types[coord] != st.EMPTY: for coord_adjustment in ((1, 0), (0, 1), (-1, 0), (0, -1)): adjacent_coord = coordinates.add(coord, coord_adjustment) if (adjacent_coord[0] >= 0 and adjacent_coord[0] < NUM_SECTORS_X and adjacent_coord[1] >= 0 and adjacent_coord[1] < NUM_SECTORS_Y): sector_is_accessible[adjacent_coord] = True for accessible in sector_is_accessible.items(): if sector_types[accessible[0]] != 0 and not accessible[1]: # Oops. Give up and try again. return randomDungeon() entrance_sector = rng.choice([coords for coords in sector_types.keys() if sector_types[coords] in (st.ROOM, st.DOUBLE_ROOM)]) exit_sector = rng.choice([coords for coords in sector_types.keys() if sector_types[coords] in (st.ROOM, st.DOUBLE_ROOM)]) entrance_coords = rng.randomPointInRect(room_nwcoords[entrance_sector], room_secoords[entrance_sector]) exit_coords = rng.randomPointInRect(room_nwcoords[exit_sector], room_secoords[exit_sector]) ret_dungeon = level.empty_dungeon(map_dimensions) for coord in sector_list: if sector_types[coord] != st.EMPTY: if sector_types[coord] == st.CORRIDOR: fill_glyph = level.CORRIDOR_GLYPH else: fill_glyph = level.ROOM_INTERIOR_GLYPH arrays.fill_rect(ret_dungeon, room_nwcoords[coord], room_secoords[coord], fill_glyph) # If there is another room to the south or east, make a corridor from this room # to it. for coord_adjustment in ((1, 0), (0, 1)): adjacent_coord = coordinates.add(coord, coord_adjustment) if (adjacent_coord[0] < NUM_SECTORS_X and adjacent_coord[1] < NUM_SECTORS_Y and sector_types[adjacent_coord] != 0): make_corridor(ret_dungeon, rng.randomPointInRect(room_nwcoords[coord], room_secoords[coord]), rng.randomPointInRect(room_nwcoords[adjacent_coord], room_secoords[adjacent_coord])) # If the room type is DOUBLE_ROOM, bolt on a second room to the first. # This room can overflow! That is intentional. if sector_types[coord] == st.DOUBLE_ROOM: max_second_se = (room_secoords[coord][0] + MIN_ROOM_SIZE, room_secoords[coord][1] + MIN_ROOM_SIZE) (second_nw, second_se) = choose_room_corners( room_nwcoords[coord], max_second_se) arrays.fill_rect(ret_dungeon, second_nw, second_se, level.ROOM_INTERIOR_GLYPH) ret_dungeon[entrance_coords] = level.UPSTAIRS_GLYPH ret_dungeon[exit_coords] = level.DOWNSTAIRS_GLYPH return ret_dungeon
def useCard(self, card_id): """ Use a card (asking the player for required information). card_id - the ID (CARD_1, CARD_2, etc.) of the card to be used. Returns the action decided upon. """ if card_id == -1 or card_id >= len(self.deck.hand): return action.DoNothing() else: card_to_use = self.deck.hand[card_id] # If the card is directional, get the direction to use it in. if card_to_use.is_directional: direction_of_target_square = kb.direction_question( self.currentLevel.messages, "In which direction would you like to use the %s card?" % card_to_use.ability_name) if direction_of_target_square is None: self.currentLevel.messages.say("Never mind.") return action.DoNothing() if card_to_use.is_melee: target_square = coordinates.add( self.coords, direction_of_target_square) if target_square in self.currentLevel.dudeLayer: del self.deck.hand[card_id] return action.SpecialMelee(self, self.currentLevel.dudeLayer[target_square], card_to_use.action_code) else: self.currentLevel.messages.say("You whiff completely!") del self.deck.hand[card_id] return action.Wait(self) else: if card_to_use.action_code == "GRENTHROW": target_square = coordinates.add(self.coords, coordinates.multiply(direction_of_target_square, 2)) if self.currentLevel.isEmpty(target_square): # Note that the player can, in fact, throw grenades on top of monsters. del self.deck.hand[card_id] return action.ThrowGrenade(self, target_square) else: self.currentLevel.messages.say( "There's something in the way!") return action.DoNothing() elif card_to_use.action_code == "ARROW": del self.deck.hand[card_id] return action.FireArrow( self, direction_of_target_square, 12) elif card_to_use.action_code == "POUNCE": del self.deck.hand[card_id] return action.Pounce(self, direction_of_target_square, 12) elif card_to_use.action_code == "HASTE": del self.deck.hand[card_id] return action.HasteMonster(self, self, 12) elif card_to_use.action_code == "HASTEALL": del self.deck.hand[card_id] return action.HasteAll(self, 8, True, True) assert False assert False
def getAction(self): while 1: key = kb.getKey() # If the key is the quit key, quit. if key == kp.QUIT: sys.exit(0) # If the key is the save key, ask if the player wants to save, and do so. elif key == kp.SAVE: if self.currentLevel.elements[self.coords] == level.UPSTAIRS_GLYPH: decision = kb.boolean_question(self.currentLevel.messages, "Do you really want to save and quit the game?") if decision: raise exc.SavingLevelChange() else: self.currentLevel.messages.say("Never mind, then.") return action.DoNothing() else: self.currentLevel.messages.say("You can only save when on the stairs (<).") # If the key is the wait key, wait. elif key == kp.WAIT: return action.Wait(self) # If the key is a movement key, move or attack, as is appropriate. elif key in config.DIRECTION_SWITCH: target = coordinates.add(self.coords, config.DIRECTION_SWITCH[key]) if target in self.currentLevel.dudeLayer: return action.Attack(self, self.currentLevel.dudeLayer[target]) elif self.canMove(target): # If the player is stuck, he cannot move! if self.hasCondition("stuck"): self.currentLevel.messages.append("You are stuck and cannot move!") return action.DoNothing() else: return action.Move(self, config.DIRECTION_SWITCH[key]) else: # A move is illegal! return action.DoNothing() elif key in config.RUN_DIRECTION_SWITCH: direction = config.RUN_DIRECTION_SWITCH[key] target = coordinates.add(self.coords, direction) if len(self.fov.dudes) != 0: self.currentLevel.messages.append("Not with enemies in view!") return action.DoNothing() elif self.canMove(target): # If the player is stuck, he cannot move. if self.hasCondition("stuck"): self.currentLevel.messages.append("You are stuck and cannot move!") return action.DoNothing() else: self.giveCondition(cond.Running(direction)) return action.Move(self, direction) # If the key requests that a card be used, prompt for a card, then use it. elif key == kp.FIRE: if len(self.deck.hand) == 0: self.currentLevel.messages.append( "You have no cards to use!") return action.DoNothing() else: card_id = kb.card_question(self.currentLevel.messages, "Which card do you want to evoke?", self.deck) if card_id == -1: return action.DoNothing() else: return self.useCard(card_id) elif key == kp.HEAL: # Have the player use a card to heal wounds. card_id = kb.card_question(self.currentLevel.messages, "Which card will you sacrifice for your health?", self.deck) if card_id == -1: return action.DoNothing() else: del self.deck.hand[card_id] return action.Heal(self, self, rng.XdY(2, 7 + self.char_level), False) # If the key is the "go upstairs" key, try to go up a level. elif key == kp.UP: if self.currentLevel.elements[self.coords] == level.UPSTAIRS_GLYPH: return action.Up()
def getAction(self): while 1: key = kb.getKey() # If the key is the quit key, quit. if key == kp.QUIT: sys.exit(0) # If the key is the save key, ask if the player wants to save, and do so. elif key == kp.SAVE: if self.currentLevel.elements[self.coords] == level.UPSTAIRS_GLYPH: decision = kb.boolean_question(self.currentLevel.messages, "Do you really want to save and quit the game?") if decision: raise exc.SavingLevelChange() else: self.currentLevel.messages.say("Never mind, then.") return action.DoNothing() else: self.currentLevel.messages.say("You can only save when on the stairs (<).") # If the key is the wait key, wait. elif key == kp.WAIT: return action.Wait(self) # If the key is a movement key, move or attack, as is appropriate. elif key in config.DIRECTION_SWITCH: target = coordinates.add(self.coords, config.DIRECTION_SWITCH[key]) if target in self.currentLevel.dudeLayer: return action.Attack(self, self.currentLevel.dudeLayer[target]) elif self.canMove(target): # If the player is stuck, he cannot move! if self.hasCondition("stuck"): self.currentLevel.messages.append("You are stuck and cannot move!") return action.DoNothing() else: return action.Move(self, config.DIRECTION_SWITCH[key]) else: # A move is illegal! return action.DoNothing() elif key in config.RUN_DIRECTION_SWITCH: direction = config.RUN_DIRECTION_SWITCH[key] target = coordinates.add(self.coords, direction) if len(self.fov.dudes) != 0: self.currentLevel.messages.append("Not with enemies in view!") return action.DoNothing() elif self.canMove(target): # If the player is stuck, he cannot move. if self.hasCondition("stuck"): self.currentLevel.messages.append("You are stuck and cannot move!") return action.DoNothing() else: self.giveCondition(cond.Running(direction)) return action.Move(self, direction) # If the key is a card key, use the card. elif key in kb.card_values: card_id = kb.card_values[key] if card_id >= len(self.deck.hand): return action.DoNothing() card_to_use = self.deck.hand[card_id] # If the card is directional, get the direction to use it in. if card_to_use.is_directional: direction_of_target_square = kb.direction_question( self.currentLevel.messages, "In which direction would you like to use the %s card?" % card_to_use.ability_name) if card_to_use.is_melee: target_square = coordinates.add(self.coords, direction_of_target_square) if target_square in self.currentLevel.dudeLayer: del self.deck.hand[card_id] return action.SpecialMelee(self, self.currentLevel.dudeLayer[target_square], card_to_use.action_code) else: self.currentLevel.messages.say("You whiff completely!") del self.deck.hand[card_id] return action.Wait(self) else: if card_to_use.action_code == "GRENTHROW": target_square = coordinates.add(self.coords, coordinates.multiply(direction_of_target_square, 2)) if self.currentLevel.isEmpty(target_square) and (not events.is_grenade_at_coords(target_square, self.currentLevel)): del self.deck.hand[card_id] return action.ThrowGrenade(self, target_square) else: self.currentLevel.messages.say("There's something in the way!") return action.DoNothing() elif card_to_use.action_code == "ARROW": del self.deck.hand[card_id] return action.FireArrow(self, direction_of_target_square, 12) elif card_to_use.action_code == "HASTE": del self.deck.hand[card_id] return action.HasteMonster(self, self, 12) elif card_to_use.action_code == "HASTEALL": del self.deck.hand[card_id] return action.HasteAll(self, 8) assert False assert False elif key == kp.REST: # Give the player the "rest" status, so she waits until healed fully. self.giveCondition(cond.Resting()) return action.Wait(self) # If the key is the "go upstairs" key, try to go up a level. elif key == kp.UP: if self.currentLevel.elements[self.coords] == level.UPSTAIRS_GLYPH: return action.Up()