def random_magic_weapon(dungeon_level=1): item = random_weapon(dungeon_level=dungeon_level) dice = randint(1, 1000) item.add_component(IdentifiableWeapon(item.base_name), "identifiable") naming = Naming(item.base_name) if (dice <= 500): naming.prefix = "Remarkable" item.color = COLORS.get('equipment_uncommon') item.equippable.number_of_dice = 2 elif (dice <= 750): naming.prefix = "Excellent" item.color = COLORS.get('equipment_rare') item.equippable.number_of_dice = 3 elif (dice <= 900): naming.prefix = "Exceptional" item.color = COLORS.get('equipment_epic') item.equippable.number_of_dice = 4 elif (dice <= 950): naming.prefix = "Phenomenal" item.color = COLORS.get('equipment_legendary') item.equippable.number_of_dice = 5 else: create_unique_weapon(item) item.add_component(naming, 'naming') add_random_weapon_ablity(item) return item
def __init__(self, blocked=False, block_sight=False): super(CavernFloor, self).__init__(blocked, block_sight) self.fov_color = COLORS.get('light_cavern_floor') self.out_of_fov_color = COLORS.get('dark_cavern_floor') self.name = "Cavern floor" self.char = choice([',', '`', ';', "'"])
def update_and_draw_layout(self): for x, y in self: wall = self.is_wall(x, y) if self.visible(x, y): if wall: self.update_and_draw_char(x, y, ' ', fg=None, bg=COLORS.get('light_wall')) else: self.update_and_draw_char(x, y, ' ', fg=None, bg=COLORS.get('light_ground')) self.explored[x, y] = True elif self.explored[x, y]: if wall: self.update_and_draw_char(x, y, ' ', fg=None, bg=COLORS.get('dark_wall')) else: self.update_and_draw_char(x, y, ' ', fg=None, bg=COLORS.get('dark_ground'))
def __init__(self, blocked=True, block_sight=True): super(CorridorWall, self).__init__(blocked, block_sight) self.fov_color = COLORS.get('light_cavern_wall') self.out_of_fov_color = COLORS.get('dark_cavern_wall') self.name = "Corridor wall" self.char = '#'
def __init__(self, blocked=False, block_sight=False): super(InternalDoor, self).__init__(blocked, block_sight) self.fov_color = COLORS.get('light_door_tile') self.out_of_fov_color = COLORS.get('dark_door_tile') self.name = "Room Floor" self.char = '.'
def __init__(self, blocked=False, block_sight=False): super(CorridorFloor, self).__init__(blocked, block_sight) self.fov_color = COLORS.get('light_room_floor') self.out_of_fov_color = COLORS.get('dark_room_floor') self.name = "Corridor floor" self.char = '.'
def __init__(self, blocked=True, block_sight=True): super(RoomWall, self).__init__(blocked, block_sight) self.fov_color = COLORS.get('light_room_wall') self.out_of_fov_color = COLORS.get('dark_room_wall') self.name = "Wall" self.char = '#'
def __init__(self, blocked=False, block_sight=False): super(ShallowWater, self).__init__(blocked, block_sight) self.fov_color = COLORS.get('light_shallow_water') self.out_of_fov_color = COLORS.get('dark_shallow_water') self.name = "Shallow water" self.char = chr(247)
def place_stairs(self): exit = find(lambda room: room.name == 'exit', self.current_level.rooms) if (exit): x, y = exit.center self.down_stairs = Entity(Point(x, y), '>', 'Stairs', COLORS.get('stairs'), render_order=RenderOrder.STAIRS, always_visible=True) self.down_stairs.add_component(Stairs(self.dungeon_level + 1), "stairs") self.current_level.add_entity(self.down_stairs) entrance = find(lambda room: room.name == 'entrance', self.current_level.rooms) if (entrance): x, y = entrance.center self.up_stairs = Entity(Point(x, y), '<', 'Stairs', COLORS.get('stairs'), render_order=RenderOrder.STAIRS, always_visible=True) self.up_stairs.add_component(Stairs(self.dungeon_level - 1), "stairs") self.current_level.add_entity(self.up_stairs)
def __init__(self, blocked=True, block_sight=False): super(DeepWater, self).__init__(blocked, block_sight) self.fov_color = COLORS.get('light_deep_water') self.out_of_fov_color = COLORS.get('dark_deep_water') self.name = "Deep water" self.char = chr(247)
def lightning(**kwargs): '''Cast a lightning bolt. A bolt does ELECTRIC damage to all damagable entities in a line. The line is drawn between the caster, through the target point and stops when it hits a blocking tile. Parameters ---------- kwargs: caster (Entity): Entity that initiated the spell. game_map (GameMap): Current game map. number_of_dice (int): number of die to roll. target_x (int): x co-ordinate. target_y (int): y co-ordinate. type_of_dice (int): Type of die to roll. Returns ------- results (list) Results of casting the spell. ''' caster = kwargs.get('caster') game_map = kwargs.get('game_map') number_of_dice = kwargs.get('number_of_dice') target_x = kwargs.get('target_x') target_y = kwargs.get('target_y') type_of_dice = kwargs.get('type_of_dice') ray = bresenham_ray(game_map, (caster.x, caster.y), (target_x, target_y)) results = [] ray.pop(0) #first item is caster xy for x, y in ray: entities = game_map.current_level.entities.get_entities_in_position( (x, y)) for entity in entities: if entity.health and not entity.health.dead: damage = die_roll(number_of_dice, type_of_dice) results.append({ ResultTypes.MESSAGE: Message( f"A lighting bolt strikes the {entity.name} with a loud crack of thunder!", COLORS.get('effect_text'), target=entity, type=MessageType.EFFECT) }) damage_results, total_damage = entity.health.take_damage( damage, caster, DamageType.ELECTRIC) results.append({ ResultTypes.MESSAGE: Message(f"{entity.name} takes {str(total_damage)} damage.", COLORS.get('damage_text')) }) results.extend(damage_results) return results
def __init__(self, blocked=False, block_sight=False): super(FungalCavernFloor, self).__init__(blocked, block_sight) self.fov_color = COLORS.get('light_cavern_floor') self.out_of_fov_color = COLORS.get('dark_cavern_floor') self.foreground_color = COLORS.get('light_fungal_cavern_floor') self.name = "Fungus covered cavern floor" self.char = '"'
def render_dijkstra(self, dijkstra, console: Console) -> None: dijkstra = np.where(dijkstra == np.iinfo(np.int32).max, -1, dijkstra) max_distance = np.amax(dijkstra) for (x, y), value in np.ndenumerate(self.grid): if dijkstra[x, y] > 0: console.bg[x, y] = tcod.color_lerp( COLORS.get('dijkstra_near'), COLORS.get('dijkstra_far'), 0.9 * dijkstra[x, y] / max_distance)
def fireball(**kwargs): '''Cast a fireball. Does FIRE damage to all damagable entities in a circle centered on the target point. Parameters ---------- kwargs: caster (Entity): Entity that initiated the spell. game_map (GameMap): Current game map. number_of_dice (int): number of die to roll. radius (int): radius of the spell effect. target_x (int): x co-ordinate. target_y (int): y co-ordinate. type_of_dice (int): Type of die to roll. Returns ------- results (list) Results of casting the spell. ''' caster = kwargs.get('caster') game_map = kwargs.get('game_map') number_of_dice = kwargs.get('number_of_dice') radius = kwargs.get('radius') target_x = kwargs.get('target_x') target_y = kwargs.get('target_y') type_of_dice = kwargs.get('type_of_dice') results = [] if not game_map.current_level.fov[target_x, target_y]: results.append({ ResultTypes.MESSAGE: Message('You cannot target a tile outside your field of view.', COLORS.get('neutral_text')) }) return results results.append({ ResultTypes.MESSAGE: Message( 'The fireball explodes, burning everything within {0} tiles!'. format(radius), COLORS.get('effect_text')) }) #TODO: refactor, this is probably horribly inefficent for entity in game_map.current_level.entities: if entity.point.distance_to(Point( target_x, target_y)) <= radius and entity.health: damage = die_roll(number_of_dice, type_of_dice) damage_results, total_damage = entity.health.take_damage( damage, caster, DamageType.FIRE) results.extend(damage_results) return results
def display_color(self): if (self.health_percentage <= HealthStates.NEAR_DEATH): return COLORS.get('health_near_death') elif (self.health_percentage <= HealthStates.INJURED): return COLORS.get('health_injured') elif (self.health_percentage <= HealthStates.BARELY_INJURED): return COLORS.get('health_barely_injured') return self.owner.color
def npc_death(self, game_map): self.owner.char = '%' self.owner.color = COLORS.get('corpse') self.owner.blocks = False self.owner.render_order = RenderOrder.CORPSE pubsub.pubsub.add_message( pubsub.Publish(None, pubsub.PubSubTypes.MESSAGE, message=Message('You died!', COLORS.get('failure_text')))) return GameStates.GAME_OVER
def use(self, player): results = [] if player.harmable.hp == player.harmable.max_hp: message = Message('You are already at full health.', COLORS.get('white')) results.append({'item_consumed': (False, self.owner), 'message': message}) else: message = Message('You wounds start to heal.', COLORS.get('green')) results.append({'item_consumed': (True, self.owner), 'heal': (player, self.healing), 'message': message, 'animation': (Animations.HEALTH_POTION, player)}) return results
def orc(point=None, dungeon_level=1): #create an orc health_component = Health(20) ai_component = BasicNPC() npc = Character(point, 'O', 'orc', COLORS.get('orc'), ai=ai_component, species=Species.ORC, health=health_component, act_energy=5) npc.add_component(Offence(base_power=10), 'offence') npc.add_component(Defence(defence=4), 'defence') npc.add_component(Level(xp_value=10), 'level') npc.movement.routing_avoid.extend(npc_avoid) item = equipment.create_weapon('shortsword') item.lootable = False npc.inventory.add_item(item) npc.equipment.toggle_equip(item) return npc
def waterblast(game_map, center, *, radius=4, damage=6, user=None): """Create a blast of water centered at a position of a given radius. The waterblast both deals damage, and floods all tiles within a given radius. """ results = [] harmable_within_radius = (get_all_entities_with_component_within_radius( center, game_map, "harmable", radius)) for entity in (x for x in harmable_within_radius if x != user): text = f"The {entity.name} is caught in a waterblast!" message = Message(text, COLORS.get('white')) results.append({ ResultTypes.DAMAGE: (entity, None, damage, [Elements.WATER]), ResultTypes.MESSAGE: message }) blast_coordinates = coordinates_within_circle(center, radius) for coord in blast_coordinates: if game_map.walkable[coord]: entities = get_all_entities_of_type_within_radius( coord, game_map, EntityTypes.TERRAIN, 0) for entity in entities: results.append({ResultTypes.REMOVE_ENTITY: entity}) water = Water.make(game_map, coord[0], coord[1]) results.append({ResultTypes.ADD_ENTITY: water}) results.append( {ResultTypes.ANIMATION: (Animations.WATERBLAST, center, radius)}) return results
def change_power(**kwargs): '''Cast increase power. Update an entity's power by [number_of_dice]D[type_of_dice]. Parameters ---------- kwargs: caster (Entity): Entity that initiated the spell. number_of_dice (int): number of die to roll. target (Entity): The entity that is being targetted by the spell. type_of_dice (int): Type of die to roll. Returns ------- results (list) Results of casting the spell. ''' caster = kwargs.get('caster') number_of_dice = kwargs.get('number_of_dice') target = kwargs.get('target') type_of_dice = kwargs.get('type_of_dice') results = [] extra = die_roll(number_of_dice, type_of_dice) target.offence.base_power = target.offence.base_power + extra results.append({ ResultTypes.MESSAGE: Message('You feel like you can take anything on!', COLORS.get('success_text')) }) return results
def antidote(**kwargs): '''Cast antidote. Remove poisoned component from an entity (if it exists). Parameters ---------- kwargs: target (Entity): The entity that is being targetted by the spell. Returns ------- results (list) Results of casting the spell. ''' target = kwargs.get('target') results = [] if target.poisoned: results.extend(target.poisoned.end()) results.append({ ResultTypes.MESSAGE: Message(f"{target.name} feels clensed.", COLORS.get('success_text'), target=target, type=MessageType.EFFECT) }) return results
def identify(**kwargs): '''Cast identify. If and entity has the Identifiable component and identifiable.identified is FALSE, switch to TRUE and print out a description of the entity. Parameters ---------- kwargs: target (Entity): The entity that is being targetted by the spell. Returns ------- results (list) Results of casting the spell. ''' target = kwargs.get('target') results = [] if target.identifiable and not target.identifiable.identified: target.identifiable.identified = True results.append({ ResultTypes.MESSAGE: Message(f"The item is a {target.name}", COLORS.get('effect_text')) }) if target.identifiable.common_ident: results.append({ResultTypes.COMMON_IDENT: target.base_name}) return results
def mapping(**kwargs): '''Cast mapping. Reveal the entire game map. Parameters ---------- kwargs: game_map (GameMap): Current game map. Returns ------- results (list) Results of casting the spell. ''' game_map = kwargs.get('game_map') results = [] game_map.current_level.explored = np.full( game_map.current_level.grid.shape, 1, dtype=np.int8) results.append({ ResultTypes.MESSAGE: Message('The scroll contains a map of immediate area.', COLORS.get('success_text')) }) results.append({ResultTypes.FOV_RECOMPUTE: True}) return results
def render_entity_detail(self, highlighted_path, target, console: Console) -> None: if highlighted_path: for x, y in highlighted_path: console.bg[x, y] = COLORS.get('show_entity_track') if target: console.bg[target.x, target.y] = tcod.black
def __init__(self, blocked, block_sight=None): self.blocked = blocked # By default, if a tile is blocked, it also blocks sight if block_sight is None: block_sight = blocked self.block_sight = block_sight self.walkable = not self.blocked self.explored = False self.fov_color = COLORS.get('light_default') self.out_of_fov_color = COLORS.get('dark_default') self.foreground_color = COLORS.get('foreground_default') self.name = "Tile" self.char = " " self._glyph = None
def tick(self, game_map): results = [] coords = coordinates_within_circle((self.owner.x, self.owner.y), self.range) for coord in coords: entities = game_map.current_level.entities.get_entities_in_position( coord) if entities: for entity in entities: if entity == self.owner: continue if not entity.animate: continue if entity.health: damage = die_roll(self.number_of_dice, self.type_of_dice) damage_results, total_damage = entity.health.take_damage( damage, self.owner, self.damage_type) if total_damage > 0: msg = Message( f"{entity.name} takes {str(damage)} damage from {self.owner.name}'s {self.name}.", COLORS.get('damage_text'), target=entity, type=MessageType.EFFECT) results.extend(damage_results) results.extend([{ResultTypes.MESSAGE: msg}]) return results
def end(self): results = [] if not self.owner.health.dead: results.append({ ResultTypes.MESSAGE: Message( f"{self.owner.name.title()} has regained their composure", COLORS.get('effect_text'), target=self.owner, type=MessageType.EFFECT) }) self.owner.health.base_max_hp -= self.health_modifier damage_results, total_damage = self.owner.health.take_damage( self.health_modifier) results.extend(damage_results) self.owner.deregister_turn(self.uuid) try: self.owner.del_component('berserk') except AttributeError: logging.info( f"tried to remove berserk from {self.owner.name} - {self.owner.uuid}" ) return results
def bat(point=None, dungeon_level=1): health_component = Health(4) creature = Character(point, 'B', 'bat', COLORS.get('bat'), ai=PredatorNPC(species=Species.INSECT), species=Species.BAT, health=health_component, act_energy=3) creature.add_component(Offence(base_power=1), 'offence') creature.add_component(Defence(defence=1), 'defence') creature.add_component(Level(xp_value=10), 'level') teeth = equipment.teeth() teeth.lootable = False creature.inventory.add_item(teeth) creature.equipment.toggle_equip(teeth) if randint(1, 100) >= 70: equipment.add_lifedrain(teeth) creature.add_component(Naming(creature.base_name, prefix='Vampiric'), 'naming') return creature
def end(self): results = [] if self.owner: try: self.owner.del_component("poisoned") except AttributeError: logging.info( f"Tried to remove poison from {self.owner.name} - {self.owner.uuid}" ) else: logging.info('****No owner to poisoned - already deleted?') self.owner.deregister_turn(self.uuid) if not self.owner.health.dead: results.append({ ResultTypes.MESSAGE: Message( f"The poison has run its course in {self.owner.name.title()}", COLORS.get('effect_text'), target=self.owner, type=MessageType.EFFECT) }) return results
def rat(point=None, dungeon_level=1): health_component = Health(4) creature = Character(point, 'R', 'rat', COLORS.get('rat'), ai=PredatorNPC(species=Species.EGG), species=Species.RAT, health=health_component, act_energy=3) creature.add_component(Offence(base_power=1), 'offence') creature.add_component(Defence(defence=1), 'defence') creature.add_component(Level(xp_value=10), 'level') creature.movement.routing_avoid.extend(creature_avoid) teeth = equipment.teeth() teeth.lootable = False creature.inventory.add_item(teeth) creature.equipment.toggle_equip(teeth) pubsub.pubsub.subscribe( pubsub.Subscription(creature, pubsub.PubSubTypes.ATTACKED, rat_swarm)) return creature