def create_wall(*args, **kwargs): ''' recieves 3 kwargs: the_game, target_x, target_y ''' the_game = kwargs.get('the_game') target_x = kwargs.get('target_x') target_y = kwargs.get('target_y') entities = the_game.entities game_map = the_game.game_map fov_map = the_game.fov_map fov_recompute = the_game.fov_recompute results = [] if get_blocking_entity(entities, target_x, target_y): msg = Message('It\'s too heavy for you to create a wall here', tcod.yellow) results.append({'acted': False, 'message':msg}) else: msg = Message('CRUNCH! A wall is created', tcod.light_green) results.append({'acted': True, 'message': msg}) game_map.tiles[target_x][target_y].create_wall() fov_map = set_tile_fov(target_x, target_y, game_map, fov_map) fov_recompute = True #do i need to do this here?? return results
def get_item_parameters(): parameters = { 'heal': { 'amount': 4 }, 'lightning': { 'damage': 20, 'maximum_range': 5 }, 'fireball': { 'targeting': True, 'damage': 12, 'radius': 3, 'targeting_message': Message( 'Left-click a tile to cast a 3x3 fireball, or right-click to cancel', tcod.cyan) }, 'confusion': { 'targeting': True, 'targeting_message': Message( 'Left-click a Creature to cast Confusion, or right-click to cancel', tcod.cyan) }, } return parameters
def cast_fireball(*args, **kwargs): entities = kwargs.get('entities') fov_map = kwargs.get('fov_map') damage = kwargs.get('damage') radius = kwargs.get('radius') target_x = kwargs.get('target_x') target_y = kwargs.get('target_y') results = [] if not tcod.map_is_in_fov(fov_map, target_x, target_y): results.append({ 'consumed': False, 'message': Message('Out of range!', tcod.yellow) }) return results results.append({ 'consumed': True, 'message': Message(f'BOOM, burns a {radius}x{radius} area.', tcod.orange) }) for entity in entities: if entity.distance(target_x, target_y) <= radius and entity.actor: results.append({ 'message': Message(f'The {entity.name} is burned for {damage} hitpoints', tcod.red) }) results.extend(entity.actor.take_dmg(damage)) return results
def break_wall(*args, **kwargs): ''' recieves 3 kwargs: the_game, target_x, target_y ''' the_game = kwargs.get('the_game') target_x = kwargs.get('target_x') target_y = kwargs.get('target_y') entities = the_game.entities game_map = the_game.game_map fov_map = the_game.fov_map fov_recompute = the_game.fov_recompute results = [] wall = the_game.game_map.tiles[target_x][target_y].blocked if not wall:#there is a wall here msg = Message('There is no wall to break here', tcod.yellow) results.append({'acted': False, 'message':msg}) elif wall: msg = Message('CRUNCH! A wall is broken', tcod.light_green) results.append({'acted': True, 'message': msg}) game_map.tiles[target_x][target_y].destroy_wall() fov_map = set_tile_fov(target_x, target_y, game_map, fov_map) fov_recompute = True #do i need to do this here?? return results
def teleport(*args, **kwargs): the_game = kwargs.get('the_game') target_x = kwargs.get('target_x') target_y = kwargs.get('target_y') results = [] move = (target_x - the_game.player.x, target_y - the_game.player.y) move_result = move_action(the_game, move) if move_result.get('fail'): results.append({'message': Message('Cant move here!')}) else: results.append({'message': Message('ZOOM, you teleported')}) return results
def move_action(the_game, move): ''' This func needs the absolute distance it will move in (x, y) parameters ''' player_turn_results = [] dx, dy = move goto_x = the_game.player.x + dx goto_y = the_game.player.y + dy #Check if tile is blocked, atk if able to, walk if not try: if not the_game.game_map.is_blocked(goto_x, goto_y): target = get_blocking_entity(the_game.entities, goto_x, goto_y) if target: attack_results = the_game.player.actor.attack_target(target) player_turn_results.extend(attack_results) else: the_game.player.move(dx, dy) the_game.fov_recompute = True the_game.game_state = GameStates.ENEMY_TURN else: return {'fail': True} except IndexError: msg = { 'message': Message('You cannot move there, it is forbbiden', tcod.orange) } player_turn_results.append(msg) #This basically processes all msgs process_player_turn_results(the_game, player_turn_results) return {}
def use(self, item_entity, **kwargs): results = [] item_comp = item_entity.item if item_comp.use_function is None: results.append({ 'message': Message(f'The {item_entity.name} cannot be used', tcod.yellow) }) else: if item_comp.targeting and not (kwargs.get('target_x') or kwargs.get('target_y')): results.append({'targeting': item_entity}) else: kwargs = {**item_comp.function_kwargs, **kwargs} item_use_results = item_comp.use_function(self.owner, **kwargs) for item_use_result in item_use_results: if item_use_result.get('consumed'): self.remove_item(item_entity) results.extend(item_use_results) return results
def learn_skill(self, skill): results = [] if skill in self.skills: #I think I don't need this skill_learned part results.append({ 'skill_learned': False, 'message': Message('You have already learned this skill.', tcod.yellow) }) else: results.append({ 'skill_learned': True, 'message': Message(f'You have learned {skill.name}') }) self.skills.append(skill) return results
def cast_confuse(*args, **kwargs): entities = kwargs.get('entities') fov_map = kwargs.get('fov_map') target_x = kwargs.get('target_x') target_y = kwargs.get('target_y') results = [] if not tcod.map_is_in_fov(fov_map, target_x, target_y): results.append({ 'consumed': False, 'message': Message('Out of range!', tcod.yellow) }) return results for entity in entities: if entity.x == target_x and entity.y == target_y and entity.ai: confused_ai = ConfusedMonster(entity.ai, 5) confused_ai.owner = entity entity.ai = confused_ai results.append({ 'consumed': True, 'message': Message(f'{entity.name} is confused', tcod.light_green) }) break else: results.append({ 'consumed': False, 'message': Message('There is no targetable creature in this tile', tcod.yellow) }) return results
def cast_lightning(*args, **kwargs): caster = args[0] entities = kwargs.get('entities') fov_map = kwargs.get('fov_map') damage = kwargs.get('damage') maximum_range = kwargs.get('maximum_range') results = [] target = None closest_distance = maximum_range + 1 for entity in entities: if entity.actor and entity != caster and tcod.map_is_in_fov( fov_map, entity.x, entity.y): distance = caster.distance_to(entity) if distance < closest_distance: target = entity clostest_distance = distance if target: results.append({ 'consumed': True, 'target': target, 'message': Message( f'Pikachu use THUNDERBOLT! Deals {damage} to {target.name}', tcod.blue) }) results.extend(target.actor.take_dmg(damage)) else: results.append({ 'consumed': False, 'target': None, 'message': Message('No enemies in range.', tcod.red) }) return results
def move_wall(*args, **kwargs): results = [] the_game = kwargs.get('the_game') target_x = kwargs.get('target_x') target_y = kwargs.get('target_y') new_target_x = kwargs.get('new_target_x') new_target_y = kwargs.get('new_target_y') wall_to_be_moved = the_game.game_map.tiles[target_x][target_y].blocked tile_to_move_wall = the_game.game_map.tiles[new_target_x][new_target_y].blocked if not wall_to_be_moved or new_target_x is None or tile_to_move_wall: msg = Message('There is no wall to break here', tcod.yellow) results.append({'acted': False, 'message':msg}) elif wall_to_be_moved: break_wall(the_game=the_game, target_x=target_x, target_y=target_y) create_wall(the_game=the_game, target_x=new_target_x, target_y=new_target_y) results.append({'acted': True, 'message': Message('Success', tcod.cyan)}) return results
def add_item(self, item): results = [] if len(self.items) >= self.capacity: results.append({ 'item_added': None, 'message': Message('You cannot carry any more, your inventory is full', tcod.yellow) }) else: results.append({ 'item_added': item, 'message': Message(f'You pick up the {item.name}', tcod.blue) }) self.items.append(item) return results
def __init__(self): create_wall_comp = Skill(use_function=create_wall, targeting_skill=True, targeting_type='single', targeting_message=Message( 'Select tile to make wall', tcod.cyan)) create_wall_fact = Fact('Create Wall', 'Self explanatory', skill=create_wall_comp) break_wall_comp = Skill(use_function=break_wall, targeting_skill=True, targeting_type='single', targeting_message=Message( 'Select tile to destoy wall', tcod.cyan)) break_wall_fact = Fact('Break Wall', 'Self explanatory', skill=break_wall_comp) move_wall_comp = Skill(use_function=move_wall, targeting_skill=True, targeting_type='multi', targeting_message=Message( 'Select tile to move wall', tcod.cyan)) move_wall_fact = Fact('Move Wall', 'Self explanatory', skill=move_wall_comp) teleport_comp = Skill(use_function=teleport, targeting_skill=True, targeting_type='single', targeting_message=Message( 'Select tile to teleport', tcod.cyan)) teleport_fact = Fact('Teleport', 'Self explanatory', skill=teleport_comp) self.skills = [ create_wall_fact, break_wall_fact, move_wall_fact, teleport_fact ]
def pickup_action(the_game): player_turn_results = [] for entity in the_game.entities: if entity.item and entity.x == the_game.player.x and entity.y == the_game.player.y: pickup_results = the_game.player.inventory.add_item(entity) player_turn_results.extend(pickup_results) break else: the_game.msg_log.add_msg( Message('There is nothing here to pickup.', tcod.yellow)) process_player_turn_results(the_game, player_turn_results)
def kill_creature(creature): death_message = Message(f'{creature.name.capitalize()} is dead!', tcod.orange) creature.char = '%' creature.color = tcod.dark_red creature.blocks = False creature.actor = None creature.ai = None creature.name = 'remains of ' + creature.name creature.render_order = RenderOrder.CORPSE return death_message
def heal(*args, **kwargs): entity = args[0] amount = kwargs.get('amount') results = [] if entity.actor.hp == entity.actor.max_hp: results.append({ 'consumed': False, 'message': Message('You are already at full health', tcod.yellow) }) else: entity.actor.heal(amount) results.append({ 'consumed': True, 'message': Message('Your wounds are healing.', tcod.green) }) return results
def fire_action(the_game): ''' This is repeating code, create a better attack func that covers both move and fire actions Maybe create a range_attack for it to be used on entity.actor?? ''' player_turn_results = [] entities_in_fov = get_entities_in_fov(the_game.fov_map, the_game.entities) if entities_in_fov: #GOD MODE FIRING ALL TARGETS ON SIGHT if the_game.god.tog: for target in entities_in_fov: attack_results = the_game.player.actor.attack_target(target) player_turn_results.extend(attack_results) process_player_turn_results(the_game, player_turn_results) #NORMAL MODE FIRING 1 TARGET W/ MOUSE CLICK else: the_game.game_state = GameStates.TARGETING_MODE while the_game.game_state == GameStates.TARGETING_MODE: tcod.sys_check_for_event( tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, the_game.key, the_game.mouse) entities_under_mouse = get_entities_under_mouse( the_game.god, the_game.mouse, the_game.entities, the_game.fov_map) exit = handle_keys(the_game.key, the_game.game_state).get('exit') if the_game.mouse.lbutton_pressed or exit: if exit: the_game.game_state = GameStates.PLAYERS_TURN return False else: the_game.game_state = GameStates.ENEMY_TURN for entity in entities_under_mouse: if entity.actor: target = entity attack_results = the_game.player.actor.attack_target( target) player_turn_results.extend(attack_results) process_player_turn_results(the_game, player_turn_results) else: message = Message("There are no targets in range", tcod.red) the_game.msg_log.add_msg(message) the_game.game_state = GameStates.ENEMY_TURN
def attack_target(self, target): results = [] dmg = self.atk_stat - target.actor.def_stat name = self.owner.name.capitalize() if dmg > 0: results.append({ 'message': Message( f'{name} attacks {target.name} for {str(dmg)} hit points.', tcod.white) }) results.extend(target.actor.take_dmg(dmg)) else: results.append({ 'message': Message(f'{name} attacks {target.name} but deals no damage.', tcod.white) }) return results
def drop_item(self, item): results = [] item.x = self.owner.x item.y = self.owner.y self.remove_item(item) results.append({ 'item_dropped': item, 'message': Message(f'You dropped {item.name}.', tcod.yellow) }) return results
def take_turn(self, target, fov_map, game_map, entities): results = [] if self.turns_left > 0: random_x = self.owner.x + randint(0, 2) - 1 random_y = self.owner.y + randint(0, 2) - 1 if random_x != self.owner.x and random_y != self.owner.y: self.owner.move_towards(random_x, random_y, game_map, entities) self.turns_left -= 1 else: self.owner.ai = self.prev_ai results.append({ 'message': Message(f'The {self.owner.name} is no longer confused', tcod.red) }) return results
def create_wall_action(the_game): player_turn_results = [] the_game.game_state = GameStates.TARGETING_MODE ''' ############## NOTE ############## THIS WHILE LOOP WILL GENERATE PROBLEMS IN THE FUTURE, specifically with rendering animations(if i so wish to implement it) Need to find a better solution, maybe do targeting function first, and then after u get the direction u activate break_wall() ''' while the_game.game_state == GameStates.TARGETING_MODE: tcod.sys_check_for_event(tcod.EVENT_KEY_PRESS, the_game.key, the_game.mouse) x, y = handle_keys(the_game.key, the_game.game_state).get('move', (None, None)) if x is not None: the_game.game_state = GameStates.ENEMY_TURN if handle_keys(the_game.key, the_game.game_state).get('exit'): the_game.game_state = GameStates.PLAYERS_TURN return False dx, dy = the_game.player.x + x, the_game.player.y + y if get_blocking_entity(the_game.entities, dx, dy): msg = { 'message': Message( "It's too heavy for you to create a wall here, there is someone there!", tcod.orange) } player_turn_results.append(msg) process_player_turn_results(the_game, player_turn_results) return None the_game.game_map.tiles[dx][dy].create_wall() the_game.fov_map = set_tile_fov(dx, dy, the_game.game_map, the_game.fov_map) the_game.fov_recompute = True
def use_skill(self, skill_fact, **kwargs): results = [] skill_comp = skill_fact.skill if skill_comp.use_function is None: results.append( {'message': Message(f'You cant use this skill', tcod.yellow)}) else: if skill_comp.targeting_skill and not (kwargs.get('target_x') or kwargs.get('target_y')): results.append({'targeting_skill': skill_fact}) else: kwargs = {**skill_comp.function_kwargs, **kwargs} skill_use_results = skill_comp.use_function(**kwargs) #In inventory there is an extra step that is consuming the item #Not really needed here, but maybe it would be nice to check if #player has enough stamina/energy to do so... results.extend(skill_use_results) return results
def kill_player(player): player.char = '%' player.color = tcod.dark_red return Message('You died!', tcod.red), GameStates.PLAYER_DEAD
def process_player_turn_results(the_game, player_turn_results): for player_result in player_turn_results: message = player_result.get('message') dead_entity = player_result.get('dead') item_added = player_result.get('item_added') item_consumed = player_result.get('consumed') item_dropped = player_result.get('item_dropped') targeting = player_result.get('targeting') targeting_cancelled = player_result.get('targeting_cancelled') targeting_skill = player_result.get('targeting_skill') acted = player_result.get('acted') if message: the_game.msg_log.add_msg(message) if dead_entity: if dead_entity == the_game.player: message, the_game.game_state = kill_player(dead_entity) else: message = kill_creature(dead_entity) the_game.msg_log.add_msg(message) if item_added: the_game.entities.remove(item_added) the_game.game_state = GameStates.ENEMY_TURN if item_consumed: the_game.game_state = GameStates.ENEMY_TURN if item_dropped: the_game.entities.append(item_dropped) the_game.game_state = GameStates.ENEMY_TURN if targeting: the_game.prev_game_state = GameStates.PLAYERS_TURN the_game.game_state = GameStates.TARGETING_MODE the_game.targeting_item = targeting the_game.msg_log.add_msg( the_game.targeting_item.item.targeting_message) if targeting_skill: the_game.prev_game_state = GameStates.PLAYERS_TURN the_game.game_state = GameStates.TARGETING_MODE the_game.targeting_skill = targeting_skill the_game.msg_log.add_msg( the_game.targeting_skill.skill.targeting_message) if targeting_cancelled: the_game.game_state = the_game.prev_game_state the_game.msg_log.add_msg(Message('Targeting cancelled')) if acted: the_game.game_state = GameStates.ENEMY_TURN