def place_entities(self, entities: List, room: Rect): max_monsters_per_room = from_dungeon_level([[2, 1], [3, 4], [5, 6]], self.dungeon_level) max_items_per_room = from_dungeon_level([[1, 1], [2, 4]], self.dungeon_level) monster_chances = {'orc': 80, 'troll': 20} item_chances = { 'sword': from_dungeon_level([[5, 4]], self.dungeon_level), 'shield': from_dungeon_level([[15, 8]], self.dungeon_level), 'healing_potion': 70, 'lightning_scroll': 10, 'fireball_scroll': 10, 'confusion_scroll': 10, } # Placing random monsters for i in range(max_monsters_per_room): x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if len(self.get_entities(x, y)) == 0: monster_choice = random_choice_from_dict(monster_chances) # Probability of 80% to spawn Orc and 20% for Troll if monster_choice == 'orc': fighter_component = Fighter(hp=10, defense=0, power=4, xp=35) ai_component = BasicMonster() monster = Entity(x, y, "Orc", "o", libtcod.dark_green, fighter_component, ai_component, render_order=RenderOrder.ACTOR) else: fighter_component = Fighter(hp=16, defense=1, power=8, xp=100) ai_component = BasicMonster() monster = Entity(x, y, "Troll", "T", libtcod.orange, fighter_component, ai_component, render_order=RenderOrder.ACTOR) # Add the monster as an entity property of the tile to check for blocking movement # self.tiles[x][y].entity = monster self.set_entity(x, y, monster) entities.append(monster) # Placing random items for i in range(max_items_per_room): x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if len(self.get_entities(x, y)) == 0: item_choice = random_choice_from_dict(item_chances) if item_choice == 'sword': equippable_component = Equippable( EquipementSlots.MAIN_HAND, power_bonus=3) item = Entity(x, y, 'Sword', '-', libtcod.sky, equippable=equippable_component) elif item_choice == 'shield': equippable_component = Equippable(EquipementSlots.OFF_HAND, defense_bonus=1) item = Entity(x, y, 'Shield', ']', libtcod.darker_orange, equippable=equippable_component) elif item_choice == 'healing_potion': item_component = Item(use_function=heal, amount=40) item = Entity(x, y, 'Healing Potion', '!', libtcod.violet, item=item_component, render_order=RenderOrder.ITEM) elif item_choice == 'fireball_scroll': item_component = Item( use_function=cast_fireball, targeting=True, targeting_message=Message( 'Left-click a target tile for the fireball, or right-click to cancel.', libtcod.light_cyan), damage=25, radius=3) item = Entity(x, y, 'Fireball Scroll', '#', libtcod.red, item=item_component, render_order=RenderOrder.ITEM) elif item_choice == 'confusion_scroll': item_component = Item( use_function=cast_confuse, targeting=True, targeting_message=Message( 'Left-click an enemy to confuse it, or right-click to cancel.', libtcod.light_cyan), radius=3) item = Entity(x, y, 'Confusion Scroll', '#', libtcod.light_pink, item=item_component, render_order=RenderOrder.ITEM) else: item_component = Item(use_function=cast_lightning, damage=40, maximum_range=5) item = Entity(x, y, 'Lightning Scroll', '#', libtcod.yellow, item=item_component, render_order=RenderOrder.ITEM) # Add item as an entity property of the tile self.set_entity(x, y, item) entities.append(item)
def place_entities(self, room, entities): # Get a random number of monsters max_monsters_per_room = from_dungeon_level( table=[[2, 1], [3, 4], [5, 6]], dungeon_level=self.dungeon_level) max_items_per_room = from_dungeon_level( table=[[1, 1], [2, 4]], dungeon_level=self.dungeon_level) number_of_monsters: int = randint(0, max_monsters_per_room) number_of_items: int = randint(0, max_items_per_room) monster_chances = { 'orc': 80, 'troll': from_dungeon_level(table=[[15, 3], [30, 5], [60, 7]], dungeon_level=self.dungeon_level) } item_chances = { 'healing_potion': 35, 'sword': from_dungeon_level(table=[[5, 4]], dungeon_level=self.dungeon_level), 'shield': from_dungeon_level(table=[[15, 8]], dungeon_level=self.dungeon_level), 'lightning_scroll': from_dungeon_level([[25, 4]], self.dungeon_level), 'fireball_scroll': from_dungeon_level([[25, 6]], self.dungeon_level), 'confusion_scroll': from_dungeon_level([[10, 2]], self.dungeon_level) } for i in range(number_of_monsters): # Choose a random location in the room x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): monster_choice = random_choice_from_dict(monster_chances) if monster_choice == 'orc': fighter_component: Fighter = Fighter(hp=10, base_defense=0, base_power=3) ai_component: BasicMonster = BasicMonster() monster = Entity(x=x, y=y, char='o', color=terminal.color_from_argb( 0, 63, 127, 63), name='Orc', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) else: fighter_component: Fighter = Fighter(hp=16, base_defense=1, base_power=4) ai_component: BasicMonster = BasicMonster() monster = Entity(x=x, y=y, char='T', color=terminal.color_from_argb( 0, 0, 127, 0), name='Troll', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) entities.append(monster) for i in range(number_of_items): x: int = randint(room.x1 + 1, room.x2 - 1) y: int = randint(room.y1 + 1, room.y2 - 1) if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): item_choice = random_choice_from_dict(item_chances) if item_choice == 'healing_potion': item_component = Item(use_function=heal, amount=4) item: Entity = Entity(x=x, y=y, char='!', color=terminal.color_from_argb( 0, 238, 130, 238), name='Healing Potion', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'sword': equippable_component = Equippable( slot=EquipmentSlots.MAIN_HAND, power_bonus=3) item = Entity(x=x, y=y, char='/', color=terminal.color_from_argb( 0, 153, 204, 255), name='sword', equippable=equippable_component) elif item_choice == 'shield': equippable_component = Equippable( slot=EquipmentSlots.OFF_HAND, defense_bonus=1) item = Entity(x=x, y=y, char='[', color=terminal.color_from_argb( 0, 153, 204, 255), name='Shield', equippable=equippable_component) elif item_choice == 'fireball_scroll': item_component = Item( use_function=cast_fireball, targeting=True, targeting_message= '[color=blue]Left-click a target tile for the fireball, or right-click to cancel.[/color]', damage=12, radius=3) item = Entity(x=x, y=y, char='~', color=terminal.color_from_argb(0, 255, 0, 0), name='Fireball Scroll', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'confusion_scroll': item_component = Item( use_function=cast_confuse, targeting=True, targeting_message= '[color=blue]Left-click an enemy to confuse it, or right-click to cancel.[/color]' ) item = Entity(x=x, y=y, char='~', color=terminal.color_from_argb( 0, 255, 102, 255), name='Confusion Scroll', render_order=RenderOrder.ITEM, item=item_component) else: item_component = Item(use_function=cast_lightning, damage=20, maximum_range=5) item = Entity(x=x, y=y, char='~', color=terminal.color_from_argb( 0, 255, 255, 0), name='Lightning Scroll', render_order=RenderOrder.ITEM, item=item_component) entities.append(item)
def place_entities(self, room, entities): '''Place monsters and items randomly into a room on the map.''' max_monsters_per_room = from_dungeon_level([[2, 1], [3, 4], [5, 6]], self.dlevel) max_items_per_room = from_dungeon_level([[1, 1], [2, 4]], self.dlevel) number_of_monsters = randint(0, max_monsters_per_room) number_of_items = randint(0, max_items_per_room) monster_chances = { "orc": 80, "troll": from_dungeon_level([[15, 3], [30, 5], [60, 7]], self.dlevel) } item_chances = { "healing_potion": 35, "sword": from_dungeon_level([[5, 4]], self.dlevel), "shield": from_dungeon_level([[15, 8]], self.dlevel), "lightning_scroll": from_dungeon_level([[25, 4]], self.dlevel), "fireball_scroll": from_dungeon_level([[25, 6]], self.dlevel), "confusion_scroll": from_dungeon_level([[10, 2]], self.dlevel) } # place monsters for i in range(number_of_monsters): x, y = choice(room.coords) if not any([e for e in entities if e.x == x and e.y == y]): monster_choice = random_choice_from_dict(monster_chances) if monster_choice == "orc": fighter_component = Fighter(hp=20, defense=0, power=4, xp=35) ai_component = BasicMonster() inv_component = Inventory(5) soul_char = choice([".", "*", "+"]) soul_color = choice([tcod.red, tcod.orange, tcod.yellow]) m_soul = Soul(soul_char, soul_color) m_name = "Orc" + str(len(entities)) monster = Entity(len(entities), x, y, 'o', tcod.desaturated_green, m_name, blocks=True, soul=m_soul, fighter=fighter_component, ai=ai_component, inventory=inv_component, render_order=RenderOrder.ACTOR) else: fighter_component = Fighter(hp=30, defense=2, power=8, xp=100) ai_component = BasicMonster() inv_component = Inventory(10) soul_char = choice(["*", "+"]) soul_color = choice([tcod.orange, tcod.yellow, tcod.green]) m_soul = Soul(soul_char, soul_color) m_name = "Troll" + str(len(entities)) monster = Entity(len(entities), x, y, 'T', tcod.darker_green, m_name, blocks=True, soul=m_soul, fighter=fighter_component, ai=ai_component, inventory=inv_component, render_order=RenderOrder.ACTOR) entities.append(monster) # place items for i in range(number_of_items): x, y = choice(room.coords) if not any([e for e in entities if e.x == x and e.y == y]): item_choice = random_choice_from_dict(item_chances) if item_choice == "healing_potion": item_component = Item(use_function=heal, amount=40) item = Entity(len(entities), x, y, '!', tcod.violet, "Healing Potion", render_order=RenderOrder.ITEM, item=item_component) elif item_choice == "sword": equippable_component = Equippable(EquipmentSlots.MAIN_HAND, power_bonus=3) item = Entity(len(entities), x, y, "/", tcod.sky, "Sword", equippable=equippable_component) elif item_choice == "shield": equippable_component = Equippable(EquipmentSlots.OFF_HAND, defense_bonus=1) item = Entity(len(entities), x, y, "[", tcod.dark_orange, "Shield", equippable=equippable_component) elif item_choice == "fireball_scroll": msg_str = (f"Left-click a target tile for the fireball, " f"or right-click to cancel.") msg = Message(msg_str, tcod.light_cyan) item_component = Item(use_function=cast_fireball, targeting=True, targeting_message=msg, damage=25, radius=3) item = Entity(len(entities), x, y, "#", tcod.red, "Fireball Scroll", render_order=RenderOrder.ITEM, item=item_component) elif item_choice == "confusion_scroll": msg_str = (f"Left-click an enemy to confuse it, " f"or right-click to cancel") msg = Message(msg_str, tcod.light_cyan) item_component = Item(use_function=cast_confuse, targeting=True, targeting_message=msg) item = Entity(len(entities), x, y, "#", tcod.light_pink, "Confusion Scroll", render_order=RenderOrder.ITEM, item=item_component) else: item_component = Item(use_function=cast_lightning, damage=40, max_range=5) item = Entity(len(entities), x, y, "#", tcod.yellow, "Lightning Scroll", render_order=RenderOrder.ITEM, item=item_component) entities.append(item)
from components.ai import HostileEnemy, BaseAI from components import consumable from components.fighter import Fighter from components.inventory import Inventory from entity import Actor, Item player = Actor( char="@", color=(255, 255, 255), name="Player", ai_cls=BaseAI, fighter=Fighter(hp=30, defense=2, power=5), inventory=Inventory(capacity=26), ) orc = Actor( char="o", color=(63, 127, 63), name="Orc", ai_cls=HostileEnemy, fighter=Fighter(hp=10, defense=0, power=3), inventory=Inventory(capacity=0), ) troll = Actor( char="T", color=(0, 127, 0), name="Troll", ai_cls=HostileEnemy, fighter=Fighter(hp=16, defense=1, power=4), inventory=Inventory(capacity=0),
def place_entities(self, room, entities): max_monsters_per_room = from_dungeon_level([[2, 1], [3, 4], [5, 6]], self.dungeon_level) max_items_per_room = from_dungeon_level([[ 1, 1, ], [2, 4]], self.dungeon_level) # Get a random number of monsters number_of_monsters = randint(0, max_monsters_per_room) number_of_items = randint(0, max_items_per_room) monster_chances = { 'orc': 80, 'troll': from_dungeon_level([[15, 3], [30, 5], [60, 7]], self.dungeon_level) } item_chances = { 'healing_potion': 35, 'sword': from_dungeon_level([[5, 4]], self.dungeon_level), 'shield': from_dungeon_level([[15, 8]], self.dungeon_level), 'lightning_scroll': from_dungeon_level([[25, 4]], self.dungeon_level), 'fireball_scroll': from_dungeon_level([[25, 6]], self.dungeon_level), 'confusion_scroll': from_dungeon_level([[10, 2]], self.dungeon_level) } for i in range(number_of_monsters): # Choose a random location in the room x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): monster_choice = random_choice_from_dict(monster_chances) if monster_choice == 'orc': fighter_component = Fighter(hp=20, defense=0, power=4, xp=35) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.desaturated_green, 'Orc', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) else: fighter_component = Fighter(hp=30, defense=2, power=8, xp=100) ai_component = BasicMonster() monster = Entity(x, y, 'T', libtcod.darker_green, 'Troll', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) entities.append(monster) for i in range(number_of_items): x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): item_choice = random_choice_from_dict(item_chances) if item_choice == 'healing_potion': item_component = Item(use_function=heal, amount=40) item = Entity(x, y, '!', libtcod.violet, 'Healing Potion', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'sword': equippable_component = Equippable(EquipmentSlots.MAIN_HAND, power_bonus=3) item = Entity(x, y, '/', libtcod.sky, 'Sword', equippable=equippable_component) elif item_choice == 'shield': equippable_component = Equippable(EquipmentSlots.OFF_HAND, defense_bonus=1) item = Entity(x, y, '[', libtcod.darker_orange, 'Shield', equippable=equippable_component) elif item_choice == 'fireball_scroll': item_component = Item( use_function=cast_fireball, targeting=True, targeting_message=Message( 'Left-click a target tile for the fireball, or right-click to cancel', libtcod.light_cyan), damage=25, radius=3) item = Entity(x, y, '#', libtcod.red, 'Fireball Scroll', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'confusion_scroll': item_component = Item( use_function=cast_confuse, targeting=True, targeting_message=Message( 'Left-click an enemy to confuse it, or right-click to cancel.', libtcod.light_cyan)) item = Entity(x, y, '#', libtcod.light_pink, 'Confusion Scroll', render_order=RenderOrder.ITEM, item=item_component) else: item_component = Item(use_function=cast_lightning, damage=40, maximum_range=5) item = Entity(x, y, '#', libtcod.yellow, 'Lightning Scroll', render_order=RenderOrder.ITEM, item=item_component) entities.append(item)
def take_turn(self, target, fov_map, game_map, entities, constants): results = [] monster = self.owner if libtcod.map_is_in_fov(fov_map, monster.x, monster.y): chance = randint(0, 100) if chance <= self.randomfactor: 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) else: if monster.distance_to(target) >= 2: monster.move_astar(target, entities, game_map) elif target.fighter.hp > 0: attack_results = monster.fighter.attack(target, constants) results.extend(attack_results) dice = randint(0, 100) if dice < self.ratchanceperturn: fighter_component = Fighter(hp=3, defense=0, power=3, speed=10, xp=5) ai_component = BasicMonster() spot_blocked = True while spot_blocked: x = self.owner.x + randint(-1, 1) y = self.owner.y + randint(-1, 1) if x < game_map.width and y < game_map.height: if not any([ entity for entity in entities if entity.x == x and entity.y == y and entity.fighter ]): if not game_map.tiles[x][ y].block_sight or game_map.tiles[x][ y].empty_space: spot_blocked = False monster = Entity(x, y, 304, libtcod.Color(191, 191, 191), 'rat', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) entities.append(monster) elif dice < self.ratchanceperturn + self.princechanceperturn + 1: fighter_component = Fighter(hp=5, defense=0, power=3, speed=10, xp=15) ai_component = BasicMonster() spot_blocked = True while spot_blocked: x = self.owner.x + randint(-1, 1) y = self.owner.y + randint(-1, 1) if x < game_map.width and y < game_map.height: if not any([ entity for entity in entities if entity.x == x and entity.y == y and entity.fighter ]): if not game_map.tiles[x][ y].block_sight or game_map.tiles[x][ y].empty_space: spot_blocked = False monster = Entity(x, y, 330, libtcod.lighter_violet, 'rat prince', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) entities.append(monster) return results
def main(): screen_width = 80 screen_height = 50 #map definition map_width = 80 map_height = 45 room_max_size = 10 room_min_size = 6 max_rooms = 30 max_monsters_per_room = 3 #FOV configuration fov_algorithm = 'BASIC' fov_light_walls = True fov_radius = 10 #color list colors = { 'dark_wall': (0, 0, 100), 'dark_ground': (50, 50, 150), 'light_wall': (130, 110, 50), 'light_ground': (200, 180, 50), 'dark_brown': (51, 25, 0), 'slate_gray': (112, 128, 144), 'crimson': (220, 20, 60) } #end definition tdl.set_font('arial10x10.png', greyscale=True, altLayout=True) fighter_component = Fighter(hp=30, defense=2, power=5) player = Entity(0, 0, '@', (255, 255, 255), 'Player', blocks=True, fighter=fighter_component) entities = [player] root_console = tdl.init( screen_width, screen_height, title='Roguelike Tutorial With extra Elbow Grease.') con = tdl.Console(screen_width, screen_height) game_map = GameMap(map_width, map_height) # make_map(game_map) make_map(game_map, max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room, colors) fov_recompute = True game_state = GameStates.PLAYERS_TURN while not tdl.event.is_window_closed(): if fov_recompute: game_map.compute_fov(player.x, player.y, fov=fov_algorithm, radius=fov_radius, light_walls=fov_light_walls) render_all(con, entities, game_map, fov_recompute, root_console, screen_width, screen_height, colors) tdl.flush() clear_all(con, entities) fov_recompute = False for event in tdl.event.get(): if event.type == 'KEYDOWN': user_input = event break else: user_input = None if not user_input: continue action = handle_keys(user_input) move = action.get('move') bye = action.get('exit') fullscreen = action.get('fullscreen') player_turn_results = [] if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if game_map.walkable[destination_x, destination_y]: target = get_blocking_entities_at_location( entities, destination_x, destination_y) if target: # player.fighter.attack(target) attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: player.move(dx, dy) fov_recompute = True game_state = GameStates.ENEMY_TURN if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: # entity.ai.take_turn(player,game_map, entities) enemy_turn_results = entity.ai.take_turn( player, game_map, entities) for enemy_turn_result in enemy_turn_results: message = enemy_turn_result.get('message') dead_entity = enemy_turn_result.get('dead') if message: print(message) if dead_entity: pass else: game_state = GameStates.PLAYERS_TURN if bye: return True if fullscreen: tdl.set_fullscreen(not tdl.get_fullscreen()) for player_turn_result in player_turn_results: message = player_turn_result.get('message') dead_entity = player_turn_result.get('dead') if message: print(message) if dead_entity: pass # We'll do something here momentarily
from components.equipment import Equipment from components.fighter import Fighter from components.inventory import Inventory from components.level import Level from entity import Actor, Item player = Actor( char="@", color=(255, 255, 255), name="Player", ai_cls=HostileEnemy, faction="Holy", Class=Templar(), Subclass=NoClass(), equipment=Equipment(), fighter=Fighter(hp=500, base_defense=30, base_power=50,mana=150,mana_regen=20), inventory=Inventory(capacity=26), level=Level(), ) soldier = Actor( char="T", color=(255, 255, 255), name="Templar", ai_cls=HostileEnemy, faction="Holy", Class=Templar(), Subclass=Shadow(), equipment=Equipment(), fighter=Fighter(hp=150, base_defense=37, base_power=21,mana=5,mana_regen=5), inventory=Inventory(capacity=0),
def main(): # Screen size screen_width = 80 screen_height = 50 # UI settings bar_width = 20 panel_height = 7 panel_y = screen_height - panel_height message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 # Map size map_width = 80 map_height = 43 # Room definitions max_rooms = 30 room_min_size = 6 room_max_size = 10 # FoV configurations fov_algorithm = 0 # use defualt algorithm fov_light_walls = True # light up walls we can see fov_radius = 10 # radius of view fov_recompute = True # flag to trigger FoV computations # Monster spawning settings max_monsters_per_room = 3 # Define colors to be used in FoV colors = { "dark_wall": libtcod.Color(0, 0, 100), "dark_ground": libtcod.Color(50, 50, 150), "light_wall": libtcod.Color(130, 110, 50), "light_ground": libtcod.Color(200, 180, 50), } # Font settings libtcod.console_set_custom_font( "arial10x10.png", libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) # Player initialization fighter_component = Fighter( hp=30, defense=2, power=5) # define a fighter component for the player inventory_component = Inventory(26) # Inventory component for the player player = Entity( 0, 0, "@", libtcod.white, "Player", blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, inventory=inventory_component, ) # World entity list entities = [player] # Map object game_map = GameMap(map_width, map_height) game_map.make_map( max_rooms, room_min_size, room_max_size, player, entities, max_monsters_per_room=max_monsters_per_room, ) # Fov map object fov_map = initialize_fov(game_map) # Game state game_state = GameStates.PLAYERS_TURN previous_game_state = game_state # For item targeting targeting_item = None # Creating screen libtcod.console_init_root(screen_width, screen_height, "Roguelike using libtcod", False) # Console object console = libtcod.console.Console(screen_width, screen_height) # Panel object panel = libtcod.console.Console(screen_width, panel_height) # Message Log object message_log = MessageLog(message_x, message_width, message_height) # input objects key = libtcod.Key() mouse = libtcod.Mouse() # Game loop while not libtcod.console_is_window_closed(): # Capture input events libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) # Trigger FoV calculation if fov_recompute == True: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) # Initial screen config render_all( con=console, panel=panel, entities=entities, player=player, game_map=game_map, fov_map=fov_map, fov_recompute=fov_recompute, message_log=message_log, screen_width=screen_width, screen_height=screen_height, bar_width=bar_width, panel_height=panel_height, panel_y=panel_y, mouse=mouse, colors=colors, gs=game_state, ) fov_recompute = False libtcod.console_flush() # Clear all entities clear_all(console, entities) # Capture action for given input action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) # Map values for each action move = action.get("move") pickup = action.get("pickup") show_inventory = action.get("show_inventory") drop_inventory = action.get("drop_inventory") inv_index = action.get("inventory_index") left_click = mouse_action.get("left_click") right_click = mouse_action.get("right_click") _exit = action.get("exit") fullscreen = action.get("fullscreen") player_turn_results = [] # Handle movement. Check if this is players turn if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move dest_x, dest_y = player.x + dx, player.y + dy if not game_map.is_blocked(dest_x, dest_y): target = get_blocking_entities_at_location( entities, dest_x, dest_y) if target: attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: player.move(dx, dy) fov_recompute = True # Now it is enemies turn game_state = GameStates.ENEMY_TURN elif pickup and game_state == GameStates.PLAYERS_TURN: for entity in entities: if entity.item and entity.x == player.x and entity.y == player.y: pickup_results = player.inventory.add_item(entity) player_turn_results.extend(pickup_results) break else: message_log.add_message( Message("There's nothing to pickup", color=libtcod.yellow)) # Show player inventory if show_inventory: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY # Drop item dialog if drop_inventory: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY if (inv_index is not None and previous_game_state != GameStates.PLAYER_DEAD and inv_index < len(player.inventory.items)): item = player.inventory.items[inv_index] if game_state == GameStates.SHOW_INVENTORY: player_turn_results.extend( player.inventory.use(item, entities=entities, fov_map=fov_map)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) if game_state == GameStates.TARGET_MODE: if left_click: target_x, target_y = left_click item_use_results = player.inventory.use( targeting_item, entities=entities, fov_map=fov_map, target_x=target_x, target_y=target_y, ) player_turn_results.extend(item_use_results) elif right_click: player_turn_results.append({"targeting_cancelled": True}) # Handle game exit if _exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY): game_state = previous_game_state elif game_state == GameStates.TARGET_MODE: player_turn_results.append({"targeting_cancelled": True}) else: return True # toggle fullscreen if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) # Cycle through players action log for player_turn_result in player_turn_results: message = player_turn_result.get("message") dead_entity = player_turn_result.get("dead") item_added = player_turn_result.get("item_added") item_consumed = player_turn_result.get("consumed") item_dropped = player_turn_result.get("item_dropped") targeting = player_turn_result.get("targeting") cancelled_targeting = player_turn_result.get("targeting_cancelled") if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(player) else: message = kill_monster(dead_entity) message_log.add_message(message) if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN if item_consumed: game_state = GameStates.ENEMY_TURN if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGET_MODE targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) if cancelled_targeting: game_state = previous_game_state player_turn_result.get("targeting") # After all input is handle, check if this is enemies turn if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities) # Cycle through players action log for enemy_turn_result in enemy_turn_results: message = enemy_turn_result.get("message") dead_entity = enemy_turn_result.get("dead") if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(player) else: message = kill_monster(dead_entity) message_log.add_message(message) # If player has died, no need to continue with enemies if game_state == GameStates.PLAYER_DEAD: break else: game_state = GameStates.PLAYERS_TURN
def main(): screen_width: int = 80 screen_height: int = 35 bar_width: int = 20 panel_height: int = 7 panel_y: int = screen_height - panel_height ui_layer = 10 message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 map_width = 80 map_height = 28 max_monsters_per_room = 3 con = Console(x=0, y=0, width=screen_width, height=screen_height) panel = Console(0, panel_y, screen_width, panel_height, layer=ui_layer) title = "Rogue Alchemist" font = "mplus-1p-regular.ttf" fighter_component = Fighter(hp=30, defense=2, power=5) player = Entity(x=0, y=0, char='@', color=Color.BLACK, name='Player', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component) entities = [player] game_map = GameMap(map_width, map_height) game_map.generate_dungeon(player, entities, max_monsters_per_room) # game_map.generate_dungeon(map_width, map_height, cave=True) start_room = game_map.dungeon.rooms[0] fov_algorithm = 0 fov_light_walls = True fov_radius = 10 colors = { "dark_wall": Color.DARK_SLATE_GRAY, "dark_ground": Color.DIM_GRAY, "light_wall": Color.LIGHT_SLATE_GRAY, "light_ground": Color.LIGHT_GRAY, "dark_door": Color.SADDLE_BROWN, "light_door": Color.BROWN, "test": Color.GOLD, } fov_recompute = True fov_map = initialize_fov(game_map) message_log = MessageLog(message_x, message_width, message_height) key = None blt.open() # initializes BearLib Terminal instance with default parameters terminal_options = f"window: title={title}, size={str(screen_width)}x{str(screen_height)}; font:{font}, size=12" blt.set(terminal_options) game_state = GameStates.PLAYERS_TURN while True: if fov_recompute: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) render_all(entities, player, game_map, fov_map, fov_recompute, message_log, screen_width, screen_height, bar_width, panel_height, panel_y, colors) blt.refresh() fov_recompute = False # remove player's previous position clear_all(entities) if blt.has_input(): # if no inputs, don't wait key = blt.read() action = handle_keys(key) key = None movement = action.get("move") exit_game = action.get("exit") player_turn_results = [] if movement and game_state == GameStates.PLAYERS_TURN: dx, dy = movement destination_x = player.x + dx destination_y = player.y + dy if not game_map.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location( entities, destination_x, destination_y) if target: attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: player.move(*movement) fov_recompute = True game_state = GameStates.ENEMY_TURN if exit_game: blt.close() return True for player_turn_result in player_turn_results: message = player_turn_result.get("message") dead_entity = player_turn_result.get("dead") if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GameStates.ENEMY_TURN: for entity in entities: visible = libtcod.map_is_in_fov(fov_map, entity.x, entity.y) if entity.ai: enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities) for enemy_turn_result in enemy_turn_results: message = enemy_turn_result.get("message") dead_entity = enemy_turn_result.get("dead") if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break game_state = GameStates.PLAYERS_TURN
def place_entities(self, room, entities): max_monsters_per_room = from_dungeon_level( [[2, 1], [3, 4], [5, 6], [7, 10]], self.dungeon_level) min_monsters_per_room = from_dungeon_level( [[0, 1], [1, 4], [2, 6], [6, 10], [3, 11]], self.dungeon_level) max_items_per_room = from_dungeon_level([[1, 1], [2, 4], [3, 7]], self.dungeon_level) # Get a random number of monsters number_of_monsters = randint(min_monsters_per_room, max_monsters_per_room) number_of_items = randint(0, max_items_per_room) monster_chances = { 'kanga': from_dungeon_level([[25, 3], [70, 6], [5, 10], [70, 11], [30, 16]], self.dungeon_level), 'dingo': from_dungeon_level([[60, 1], [45, 4], [20, 7], [5, 10], [20, 11]], self.dungeon_level), 'joey': from_dungeon_level([[20, 1], [15, 2], [10, 3], [0, 10], [10, 11]], self.dungeon_level), 'goanna': from_dungeon_level( [[20, 6], [70, 9], [10, 10], [70, 11], [55, 16]], self.dungeon_level), 'killer_bees': from_dungeon_level([[5, 1], [100, 10], [5, 11]], self.dungeon_level), 'dropbear': from_dungeon_level( [[15, 9], [5, 10], [35, 11], [55, 14], [70, 16]], self.dungeon_level) } item_chances = { 'lesser_med_kit': from_dungeon_level([[25, 1], [20, 5], [1, 7]], self.dungeon_level), 'morphine_pack': from_dungeon_level([[5, 5], [20, 7], [5, 9]], self.dungeon_level), 'tentacruels': from_dungeon_level([[5, 3]], self.dungeon_level), 'energy_shield': from_dungeon_level([[15, 6]], self.dungeon_level), 'plasma_grenade': from_dungeon_level([[10, 3], [12, 5]], self.dungeon_level), 'stun_grenade': from_dungeon_level([[10, 2], [15, 4]], self.dungeon_level), 'ray_gun': from_dungeon_level([[3, 6], [5, 8]], self.dungeon_level), 'shock_charge': from_dungeon_level([[5, 1], [13, 3]], self.dungeon_level), 'med_kit': from_dungeon_level([[5, 7], [25, 9]], self.dungeon_level), 'whippy_willow_twig': from_dungeon_level([[15, 1]], self.dungeon_level), 'goanna_skin_hat': from_dungeon_level([[5, 1], [15, 3]], self.dungeon_level), 'aluminite_neck_brace': from_dungeon_level([[5, 2], [10, 4]], self.dungeon_level), 'dropbear_fur_vest': from_dungeon_level([[5, 3], [7, 6]], self.dungeon_level) } for i in range(number_of_monsters): # Choose a random location in the room x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): monster_choice = random_choice_from_dict(monster_chances) if monster_choice == 'kanga': statbase = randint(30, 45) + self.dungeon_level rand_hp = statbase * 15 rand_def = statbase rand_power = round(statbase * 2.5) rand_xp = statbase * 3 fighter_component = Fighter(hp=rand_hp, defense=rand_def, power=rand_power, xp=rand_xp) ai_component = BasicMonster() monster = Entity(x, y, 196, libtcod.Color(218, 42, 32), 'Kanga', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) elif monster_choice == 'dingo': statbase = randint(15, 20) + self.dungeon_level rand_hp = statbase * 15 rand_def = statbase rand_power = round(statbase * 3.5) rand_xp = statbase * 3 fighter_component = Fighter(hp=rand_hp, defense=rand_def, power=rand_power, xp=rand_xp) ai_component = BasicMonster() monster = Entity(x, y, 191, libtcod.Color(165, 42, 42), 'Dingo', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) elif monster_choice == 'goanna': statbase = randint(45, 55) + self.dungeon_level rand_hp = statbase * 15 rand_def = statbase rand_power = statbase * 3 rand_xp = statbase * 3 fighter_component = Fighter(hp=rand_hp, defense=rand_def, power=rand_power, xp=rand_xp) ai_component = BasicMonster() monster = Entity(x, y, 186, libtcod.Color(25, 42, 0), 'Goanna', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) elif monster_choice == 'dropbear': statbase = randint(60, 65) + self.dungeon_level rand_hp = statbase * 10 rand_def = statbase + self.dungeon_level rand_power = statbase * 4 rand_xp = statbase * 4 fighter_component = Fighter(hp=rand_hp, defense=rand_def, power=rand_power, xp=rand_xp) ai_component = BasicMonster() monster = Entity(x, y, 191, libtcod.Color(33, 33, 33), 'Dropbear', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) elif monster_choice == 'killer_bees': statbase = randint(8, 10) + self.dungeon_level rand_hp = statbase * 7 rand_def = statbase rand_power = round(statbase * 12) rand_xp = round(statbase * 2.5) fighter_component = Fighter(hp=rand_hp, defense=rand_def, power=rand_power, xp=rand_xp) ai_component = BasicMonster() monster = Entity(x, y, 201, libtcod.yellow, 'Killer Bee', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) else: statbase = randint(9, 20) + self.dungeon_level rand_hp = statbase * 15 rand_def = statbase rand_power = round(statbase * 2.5) rand_xp = statbase * 3 fighter_component = Fighter(hp=rand_hp, defense=rand_def, power=rand_power, xp=rand_xp) ai_component = BasicMonster() monster = Entity(x, y, 179, libtcod.Color(218, 42, 32), 'Joey', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) entities.append(monster) for i in range(number_of_items): x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): item_choice = random_choice_from_dict(item_chances) if item_choice == 'lesser_med_kit': item_component = Item(use_function=heal, amount=200) item = Entity(x, y, 195, libtcod.violet, 'Lesser Med Kit', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'morphine_pack': item_component = Item(use_function=morphine_pack, amount=350) item = Entity(x, y, 195, libtcod.Color(40, 30, 0), 'Morphine Pack', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'med_kit': item_component = Item(use_function=morphine_pack, amount=500) item = Entity(x, y, 195, libtcod.Color(255, 30, 0), 'Med Kit', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'tentacruels': equippable_component = Equippable(EquipmentSlots.TENTACLE, power_bonus=40) item = Entity(x, y, 218, libtcod.purple, 'Tentacruel', equippable=equippable_component) elif item_choice == 'energy_shield': equippable_component = Equippable(EquipmentSlots.TENTACLE, defense_bonus=50, max_hp_bonus=250) item = Entity(x, y, 217, libtcod.cyan, 'Energy Shield', equippable=equippable_component) elif item_choice == 'whippy_willow_twig': equippable_component = Equippable(EquipmentSlots.TENTACLE, power_bonus=15) item = Entity(x, y, 188, libtcod.Color(53, 38, 0), 'Whippy Willow Twig', equippable=equippable_component) elif item_choice == 'goanna_skin_hat': equippable_component = Equippable(EquipmentSlots.HELMET, power_bonus=5, defense_bonus=10) item = Entity(x, y, 200, libtcod.Color(20, 38, 0), 'Goanna Skin Hat', equippable=equippable_component) elif item_choice == 'aluminite_neck_brace': equippable_component = Equippable(EquipmentSlots.NECK, defense_bonus=5) item = Entity(x, y, 204, libtcod.silver, 'Aluminite Neck Brace', equippable=equippable_component) elif item_choice == 'dropbear_fur_vest': equippable_component = Equippable( EquipmentSlots.CHEST_PLATE, max_hp_bonus=100, defense_bonus=25) item = Entity(x, y, 185, libtcod.Color(30, 30, 30), 'Dropbear Fur Vest', equippable=equippable_component) elif item_choice == 'plasma_grenade': item_component = Item( use_function=use_plasma_grenade, targeting=True, targeting_message=Message( 'Left-click an enemy to lob the Plasma Grenade at it, or right-click to cancel.', libtcod.light_cyan), damage=250, radius=3) item = Entity(x, y, 193, libtcod.cyan, 'Plasma Grenade', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'ray_gun': item_component = Item(use_function=use_ray_gun, damage=80, maximum_range=11) item = Entity(x, y, 187, libtcod.Color(180, 180, 180), 'Ray Gun', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'stun_grenade': item_component = Item( use_function=use_stun_grenade, targeting=True, targeting_message=Message( 'Left-click an enemy to lob the Stun Grenade at it, or right-click to cancel.', libtcod.light_cyan)) item = Entity(x, y, 193, libtcod.Color(0, 40, 0), 'Stun Grenade', render_order=RenderOrder.ITEM, item=item_component) else: item_component = Item(use_function=use_shock_charge, damage=350, maximum_range=5) item = Entity(x, y, 194, libtcod.yellow, 'Shock Charge', render_order=RenderOrder.ITEM, item=item_component) entities.append(item)
def main(): screen_width = 80 screen_height = 50 map_width = 80 map_height = 50 room_max_size = 10 room_min_size = 6 max_rooms = 30 fov_algorithm = 'BASIC' fov_light_walls = True fov_radius = 10 max_monsters_per_room = 3 colors = { 'dark_wall': (0, 0, 100), 'dark_ground': (50, 50, 150), 'light_wall': (130, 110, 50), 'light_ground': (200, 180, 50), 'desaturated_green': (63, 127, 63), 'darker_green': (0, 127, 0) } fighter_components = Fighter(hp=30, defense=2, power=5) player = Entity(0, 0, '@', (255, 255, 255), 'player', blocks=True, fighter=fighter_components) entities = [player] tdl.set_font('arial10x10.png', greyscale=True, altLayout=True) root_console = tdl.init(screen_width, screen_height, title='Roguelike Tutorial Revised') con = tdl.Console(screen_width, screen_height) game_map = GameMap(map_width, map_height) make_map(game_map, max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room, colors) fov_recompute = True game_states = GameStates.PLAYERS_TURN while not tdl.event.is_window_closed(): if fov_recompute: game_map.compute_fov(player.x, player.y, fov=fov_algorithm, radius=fov_radius, light_walls=fov_light_walls) render_all(con, entities, game_map, fov_recompute, root_console, screen_width, screen_height, colors) tdl.flush() clear_all(con, entities) fov_recompute = False for event in tdl.event.get(): if event.type == 'KEYDOWN': user_input = event break else: user_input = None if not user_input: continue action = handle_keys(user_input) move = action.get('move') exit = action.get('exit') fullscreen = action.get('fullscreen') player_turn_results = [] if move and game_states == GameStates.PLAYERS_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if game_map.walkable[destination_x, destination_y]: target = get_blocking_entities_at_location( entities, destination_x, destination_y) if target: attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: player.move(dx, dy) fov_recompute = True game_states = GameStates.ENEMY_TURN if exit: return True if fullscreen: tdl.set_fullscreen(not tdl.get_fullscreen()) if game_states == GameStates.ENEMY_TURN: for entity in entities: if entity != player: if entity.ai: entity.ai.take_turn(player, game_map, entities) game_states = GameStates.PLAYERS_TURN
def get_monster(monster_choice, x, y): # normal orc if monster_choice == 'draugr': fighter_component = Fighter(hp=20, defense=0, power=4, xp=30, coin=10) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.Color(14, 27, 112), 'Draugr', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) elif monster_choice == 'draugrV2': fighter_component = Fighter(hp=25, defense=1, power=9, xp=45, coin=15) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.Color(14, 27, 112), 'Draugr', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) elif monster_choice == 'draugrV3': fighter_component = Fighter(hp=35, defense=4, power=23, xp=75, coin=20) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.Color(14, 27, 112), 'Draugr', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) elif monster_choice == 'draugrV4': fighter_component = Fighter(hp=40, defense=10, power=58, xp=100, coin=25) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.Color(14, 27, 112), 'Draugr', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) # fire orc elif monster_choice == 'fire_draugr': fighter_component = Fighter(hp=25, defense=2, power=17, xp=40, coin=15) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.Color(210, 26, 30), 'Fire Draugr', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) elif monster_choice == 'fire_draugrV2': fighter_component = Fighter(hp=30, defense=5, power=36, xp=60, coin=20) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.Color(210, 26, 30), 'Fire Draugr', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) elif monster_choice == 'fire_draugrV3': fighter_component = Fighter(hp=40, defense=10, power=79, xp=100, coin=25) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.Color(210, 26, 30), 'Fire Draugr', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) elif monster_choice == 'fire_draugrV4': fighter_component = Fighter(hp=50, defense=15, power=88, xp=125, coin=30) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.Color(210, 26, 30), 'Fire Draugr', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) # frost orc elif monster_choice == 'frost_draugr': fighter_component = Fighter(hp=30, defense=2, power=24, xp=50, coin=20) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.Color(0, 180, 255), 'Frost Draugr', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) elif monster_choice == 'frost_draugrV2': fighter_component = Fighter(hp=40, defense=10, power=63, xp=80, coin=25) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.Color(0, 180, 255), 'Frost Draugr', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) elif monster_choice == 'frost_draugrV3': fighter_component = Fighter(hp=50, defense=17, power=88, xp=110, coin=30) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.Color(0, 180, 255), 'Frost Draugr', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) elif monster_choice == 'frost_draugrV4': fighter_component = Fighter(hp=55, defense=25, power=95, xp=140, coin=35) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.Color(0, 180, 255), 'Frost Draugr', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) # normal troll elif monster_choice == 'troll': fighter_component = Fighter(hp=50, defense=0, power=13, xp=70, coin=20) ai_component = BasicMonster() monster = Entity(x, y, 'T', libtcod.darker_green, 'Troll', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) elif monster_choice == 'trollV2': fighter_component = Fighter(hp=75, defense=1, power=28, xp=120, coin=35) ai_component = BasicMonster() monster = Entity(x, y, 'T', libtcod.darker_green, 'Troll', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) # fire troll elif monster_choice == 'fire_troll': fighter_component = Fighter(hp=50, defense=1, power=23, xp=150, coin=40) ai_component = BasicMonster() monster = Entity(x, y, 'T', libtcod.Color(210, 26, 30), 'Fire Troll', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) elif monster_choice == 'fire_trollV2': fighter_component = Fighter(hp=80, defense=6, power=65, xp=200, coin=60) ai_component = BasicMonster() monster = Entity(x, y, 'T', libtcod.Color(210, 26, 30), 'Fire Troll', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) # frost troll elif monster_choice == 'frost_troll': fighter_component = Fighter(hp=100, defense=5, power=69, xp=200, coin=70) ai_component = BasicMonster() monster = Entity(x, y, 'T', libtcod.Color(0, 180, 255), 'Frost Troll', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) elif monster_choice == 'frost_trollV2': fighter_component = Fighter(hp=150, defense=12, power=97, xp=300, coin=90) ai_component = BasicMonster() monster = Entity(x, y, 'T', libtcod.Color(0, 180, 255), 'Frost Troll', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) # brunnmigi elif monster_choice == 'brunnmigi': fighter_component = Fighter(hp=50, defense=2, power=26, xp=170, coin=40) ai_component = BasicMonster() monster = Entity(x, y, chr(135), libtcod.Color(210, 148, 22), 'Brunnmigi', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) # fylgja elif monster_choice == 'fylgja': fighter_component = Fighter(hp=65, defense=5, power=37, xp=200, coin=70) ai_component = BasicMonster() monster = Entity(x, y, chr(133), libtcod.Color(255, 255, 255), 'Fylgja', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) # valkyrie elif monster_choice == 'valkyrie': fighter_component = Fighter(hp=100, defense=10, power=76, xp=300, coin=90) ai_component = BasicMonster() monster = Entity(x, y, chr(237), libtcod.Color(80, 60, 30), 'Valkyrie', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) # lindworm elif monster_choice == 'lindworm': fighter_component = Fighter(hp=160, defense=8, power=57, xp=340, coin=100) ai_component = BasicMonster() monster = Entity(x, y, '~', libtcod.Color(0, 0, 0), 'Lindworm', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) elif monster_choice == 'fire_lindworm': fighter_component = Fighter(hp=200, defense=10, power=86, xp=600, coin=200) ai_component = BasicMonster() monster = Entity(x, y, '~', libtcod.Color(210, 26, 30), 'Fire Lindworm', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) elif monster_choice == 'frost_lindworm': fighter_component = Fighter(hp=200, defense=10, power=108, xp=800, coin=250) ai_component = BasicMonster() monster = Entity(x, y, '~', libtcod.Color(0, 180, 255), 'Frost Lindworm', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) # vatnaevattir elif monster_choice == 'vatnaevattir': fighter_component = Fighter(hp=200, defense=0, power=78, xp=300, coin=250) ai_component = BasicMonster() monster = Entity(x, y, chr(131), libtcod.Color(0, 34, 144), 'Vatnaevattir', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) #jotunn elif monster_choice == 'jotunn': fighter_component = Fighter(hp=200, defense=8, power=130, xp=1000, coin=400) ai_component = BasicMonster() monster = Entity(x, y, chr(215), libtcod.Color(0, 180, 255), 'Jotunn', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) return monster
def main(): name = "pythonRL" screenWidth = 80 screenHeight = 50 bar_width = 20 panel_height = 7 panel_y = screenHeight - panel_height message_x = bar_width + 2 message_width = screenWidth - bar_width - 1 message_height = panel_height - 1 mapWidth = 80 mapHeight = 43 room_min_size = 6 room_max_size = 10 max_rooms = 30 fov_algorithm = 0 fov_light_walls = True fov_radius = 10 max_monsters_per_room = 3 colors = { 'dark_wall': tcod.Color(61, 31, 0), 'dark_ground': tcod.Color(41, 21, 0), 'light_wall': tcod.Color(77, 38, 0), 'light_ground': tcod.Color(56, 28, 0), 'nothing': tcod.Color(0, 0, 0) } fighter_component = Fighter(hp=30, defense=2, power=5) player = Entity(0, 0, "@", tcod.white, "Player", blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component) entities = [player] tcod.console_set_custom_font( 'arial10x10.png', tcod.FONT_TYPE_GREYSCALE | tcod.FONT_LAYOUT_TCOD) tcod.console_init_root(screenWidth, screenHeight, name, False, tcod.RENDERER_SDL2, "F", True) con = tcod.console.Console(screenWidth, screenHeight, "F") panel = tcod.console.Console(screenWidth, panel_height) game_map = GameMap(mapWidth, mapHeight) game_map.make_map(max_rooms, room_min_size, room_max_size, mapWidth, mapHeight, player, entities, max_monsters_per_room) fov_recompute = True fov_map = initialize_fov(game_map) message_log = MessageLog(message_x, message_width, message_height) key = tcod.Key() mouse = tcod.Mouse() game_state = GameStates.PLAYERS_TURN while not tcod.console_is_window_closed(): tcod.sys_check_for_event(tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, key, mouse) if fov_recompute: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) render_all(con, panel, entities, player, game_map, fov_map, fov_recompute, message_log, screenWidth, screenHeight, bar_width, panel_height, panel_y, mouse, colors) fov_recompute = False tcod.console_flush() clear_all(con, entities) action = handle_keys(key) move = action.get("move") exit = action.get("exit") fullscreen = action.get("fullscreen") generate = action.get("gen") player_turn_results = [] if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move dest_x = player.x + dx dest_y = player.y + dy if not game_map.is_blocked(dest_x, dest_y): target = get_blocking_entities_at_location( entities, dest_x, dest_y) if target: attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: player.move(dx, dy) fov_recompute = True game_state = GameStates.ENEMY_TURN if exit: return True if fullscreen: tcod.console_set_fullscreen(not tcod.console_is_fullscreen()) for player_turn_result in player_turn_results: message = player_turn_result.get("message") dead_entity = player_turn_result.get("dead") if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities) for enemy_turn_result in enemy_turn_results: message = enemy_turn_result.get("message") dead_entity = enemy_turn_result.get("dead") if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break else: game_state = GameStates.PLAYERS_TURN if generate: game_map.clear() game_map.make_map(max_rooms, room_min_size, room_max_size, mapWidth, mapHeight, player) fov_map = initialize_fov(game_map) fov_recompute = True
def place_entities(self, room, entities, max_monsters_per_room, max_items_per_room): # Get a random number of monsters number_of_monsters = randint(0, max_monsters_per_room) number_of_items = randint(0, max_items_per_room) for i in range(number_of_monsters): # Choose a random location in the room x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): if randint(0, 100) < 80: fighter_component = Fighter(hp=10, defense=0, power=3) ai_component = BasicMonster() monster = Entity(x, y, 'O', libtcod.desaturated_green, 'Orc', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) else: fighter_component = Fighter(hp=16, defense=1, power=4) ai_component = BasicMonster() monster = Entity(x, y, 'T', libtcod.darker_green, 'Troll', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) entities.append(monster) for i in range(number_of_items): x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): item_chance = randint(0, 100) if item_chance < 70: item_component = Item(use_function=heal, amount=4) item = Entity(x, y, '!', libtcod.violet, 'Healing Potion', render_order=RenderOrder.ITEM, item=item_component) elif item_chance < 80: item_component = Item( use_function=cast_fireball, targeting=True, targeting_message=Message( 'Left-click a target tile for the fireball, or right-click to cancel.', libtcod.light_cyan), damage=12, radius=3) item = Entity(x, y, '#', libtcod.red, 'Fireball Scroll', render_order=RenderOrder.ITEM, item=item_component) elif item_chance < 90: item_component = Item( use_function=cast_confuse, targeting=True, targeting_message=Message( 'Left-click an enemy to confuse it, or right-click to cancel.', libtcod.light_cyan)) item = Entity(x, y, '#', libtcod.light_pink, 'Confusion Scroll', render_order=RenderOrder.ITEM, item=item_component) else: item_component = Item(use_function=cast_lightning, damage=20, maximum_range=5) item = Entity(x, y, '#', libtcod.yellow, 'Lightning Scroll', render_order=RenderOrder.ITEM, item=item_component) entities.append(item)
def place_entities(self, room, entities,dungeon_level): max_monsters_per_room = from_dungeon_level([[2, 1], [3, 4], [5, 6]], self.dungeon_level) max_items_per_room = from_dungeon_level([[1, 1], [2, 4]], self.dungeon_level) # Get a random number of monsters number_of_monsters = randint(0, max_monsters_per_room) number_of_boss = 1 # Get a random number of items number_of_items = randint(0, max_items_per_room) # place boss in level 5 and 7 and 10 monster_chances = { 'referee': 80, 'Judge-Chair': from_dungeon_level([[15, 3], [30, 5], [60, 7]], self.dungeon_level) } item_chances = { 'energy_bar': 35, 'racket': from_dungeon_level([[5, 2]], self.dungeon_level), 'hat': from_dungeon_level([[15, 6]], self.dungeon_level), 'lightning_scroll': from_dungeon_level([[25, 4]], self.dungeon_level), 'fireball_scroll': from_dungeon_level([[25, 3]], self.dungeon_level), 'confusion_scroll': from_dungeon_level([[10, 2]], self.dungeon_level) } if dungeon_level == 10: # create boss x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) fighter_component = Fighter(hp=40, defense=10, power=30, xp=120) ai_component = BasicMonster() monster = Entity(x, y, const.Boss_tile, libtcod.desaturated_green, 'Tournament Director', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) entities.append(monster) else: for i in range(number_of_monsters): # Choose a random location in the room x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) # Check if an entity is already in that location if not any([entity for entity in entities if entity.x == x and entity.y == y]): monster_choice = random_choice_from_dict(monster_chances) if monster_choice == 'referee': fighter_component = Fighter(hp=20, defense=2, power=12, xp=35) ai_component = BasicMonster() monster = Entity(x, y, const.Referee_tile , libtcod.desaturated_green, 'Referee', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) else: fighter_component = Fighter(hp=30, defense=4, power=16, xp=80) ai_component = BasicMonster() monster = Entity(x, y, const.Judge_Chair_tile , libtcod.darker_green, 'Judge-Chair', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) entities.append(monster) for i in range(number_of_items): x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if not any([entity for entity in entities if entity.x == x and entity.y == y]): item_choice = random_choice_from_dict(item_chances) if item_choice == 'energy_bar': item_component = Item(use_function=heal, amount=40) item = Entity(x, y, const.Energy_bar , libtcod.black , 'Energy Bar', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'racket': equippable_component = Equippable(EquipmentSlots.MAIN_HAND, power_bonus=10,defense_bonus=5) item = Entity(x, y, const.Tennis_Racket_tile, libtcod.sky, 'Racket', equippable=equippable_component) elif item_choice == 'hat': equippable_component = Equippable(EquipmentSlots.OFF_HAND,power_bonus=5, defense_bonus=5) item = Entity(x, y, const.Hat_tile, libtcod.darker_orange, 'Hat', equippable=equippable_component) elif item_choice == 'fireball_scroll': item_component = Item(use_function=cast_fireball, targeting=True, targeting_message=Message( 'Left-click a target tile for the fireball, or right-click to cancel.', libtcod.light_cyan), damage=25, radius=3) item = Entity(x, y, const.Fire_ball, libtcod.red, 'Fireball Scroll', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'confusion_scroll': item_component = Item(use_function=cast_confuse, targeting=True, targeting_message=Message( 'Left-click an enemy to confuse it, or right-click to cancel.', libtcod.light_cyan)) item = Entity(x, y, '#', libtcod.light_pink, 'Confusion Scroll', render_order=RenderOrder.ITEM, item=item_component) else: item_component = Item(use_function=cast_lightning, damage=40, maximum_range=5) item = Entity(x, y, '#', libtcod.yellow, 'Lightning Scroll', render_order=RenderOrder.ITEM, item=item_component) entities.append(item)
def main(): screen_width = 80 screen_height = 50 map_width = 80 map_height = 45 room_max_size = 10 room_min_size = 6 max_rooms = 30 fov_algorithm = 0 fov_light_walls = True fov_radius = 10 max_monsters_per_room = 3 colors = { 'light_wall': libtcod.Color(82, 53, 52), 'light_ground': libtcod.Color(82, 81, 52), 'dark_wall': libtcod.Color(39, 40, 57), 'dark_ground': libtcod.Color(50, 54, 87) } fighter_component = Fighter(hp=30, defense=2, power=5) player = Entity(0, 0, '@', libtcod.white, 'Player', blocks=True, fighter=fighter_component) entities = [player] libtcod.console_set_custom_font( 'resources/arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'pyrogue', False, libtcod.RENDERER_SDL2, vsync=True) con = libtcod.console.Console(screen_width, screen_height) game_map = GameMap(map_width, map_height) game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room) fov_recompute = True fov_map = initialize_fov(game_map) game_state = GameStates.PLAYERS_TURN while True: if fov_recompute: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) render_all(con, entities, game_map, fov_map, fov_recompute, screen_width, screen_height, colors) fov_recompute = False libtcod.console_flush() clear_all(con, entities, fov_map) for event in tcod.event.wait(): if event.type == "QUIT": raise SystemExit() elif event.type == "KEYDOWN": action = handle_keys(event) move = action.get('move') exit = action.get('exit') fullscreen = action.get('fullscreen') if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if not game_map.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location( entities, destination_x, destination_y) if target: print('You kick the ' + target.name + ' in the shins, much to its annoyance!') else: player.move(dx, dy) fov_recompute = True game_state = GameStates.ENEMY_TURN if exit: return True if fullscreen: libtcod.console_set_fullscreen( not libtcod.console_is_fullscreen()) if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: entity.ai.take_turn() game_state = GameStates.PLAYERS_TURN
def place_entities(room, entities, dungeon_level, colors): max_monsters_per_room = from_dungeon_level([[2, 1], [3, 4], [5, 6]], dungeon_level) max_items_per_room = from_dungeon_level([[1, 1], [2, 4]], dungeon_level) number_of_monsters = randint(0, max_monsters_per_room) number_of_items = randint(0, max_items_per_room) monster_chances = { "husk": 60, "rusted_automaton": from_dungeon_level([[25, 3], [40, 5], [60, 7]], dungeon_level), "kobold_bandit": from_dungeon_level([[10, 3], [20, 5], [25, 7]], dungeon_level) } item_chances = { "health_drink": 40, "wicked_blade": from_dungeon_level([[15, 3]], dungeon_level), "battered_armor": from_dungeon_level([[15, 4]], dungeon_level), "hp_ring": from_dungeon_level([[10, 5]], dungeon_level), "seeker_orb": from_dungeon_level([[25, 4]], dungeon_level), "flame_grenade": from_dungeon_level([[25, 6]], dungeon_level), "scrambler": from_dungeon_level([[10, 2]], dungeon_level), "pearl": 10 } for i in range(number_of_monsters): # get a random location in the room x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if not any( [entity for entity in entities if entity.x == x and entity.y == y]): monster_choice = random_choice_from_dict(monster_chances) if monster_choice == "husk": fighter_component = Fighter(hp=15, defense=0, power=5, xp=50) ai_component = BasicMonster() # husk monster = Entity(x, y, "h", colors.get("dark_gray"), "husk", blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) elif monster_choice == "rusted_automaton": # rusted automaton fighter_component = Fighter(hp=20, defense=2, power=6, xp=75) ai_component = BasicMonster() monster = Entity(x, y, "a", colors.get("brass"), "rusted automaton", blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) elif monster_choice == "kobold_bandit": # kobold bandit fighter_component = Fighter(hp=35, defense=1, power=8, xp=100) ai_component = BasicMonster() monster = Entity(x, y, "b", colors.get("darker_flame"), "kobold bandit", blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) entities.append(monster) for i in range(number_of_items): x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if not any( [entity for entity in entities if entity.x == x and entity.y == y]): item_choice = random_choice_from_dict(item_chances) if item_choice == "health_drink": item_component = Item(use_function=heal, amount=50) item = Entity(x, y, "!", colors.get("violet"), "health drink", render_order=RenderOrder.ITEM, item=item_component) elif item_choice == "wicked_blade": equippable_component = Equippable(EquipmentSlots.MAIN_HAND, power_bonus=3) item = Entity(x, y, ")", colors.get("darker_flame"), "wicked blade", equippable=equippable_component) elif item_choice == "battered_armor": equippable_component = Equippable(EquipmentSlots.BODY, defense_bonus=1) item = Entity(x, y, "T", colors.get("darker_orange"), "battered armor", equippable=equippable_component) elif item_choice == "hp_ring": equippable_component = Equippable(EquipmentSlots.RING, max_hp_bonus=30) item = Entity(x, y, "o", colors.get("copper"), "stalwart ring", equippable=equippable_component) elif item_choice == "flame_grenade": item_component = Item( use_function=flame_grenade, targeting=True, targeting_message=Message( "Left-click where you'd like to throw the grenade, or right-click to cancel.", colors.get("light_cyan")), damage=25, radius=3) item = Entity(x, y, ".", colors.get("red"), "flame grenade", render_order=RenderOrder.ITEM, item=item_component) elif item_choice == "scrambler": item_component = Item( use_function=confuse, targeting=True, targeting_message=Message( "Left-click an enemy you'd like to confuse, or right-click to cancel.", colors.get("light_cyan"))) item = Entity(x, y, ".", colors.get("light_pink"), "scrambler", render_order=RenderOrder.ITEM, item=item_component) elif item_choice == "pearl": item_component = Item(use_function=xpboost, amount=100) item = Entity(x, y, ".", colors.get("silver"), "pearl", render_order=RenderOrder.ITEM, item=item_component) elif item_choice == "seeker_orb": item_component = Item(use_function=seeker_bolt, damage=30, maximum_range=5) item = Entity(x, y, ".", colors.get("sky"), "seeker orb", render_order=RenderOrder.ITEM, item=item_component) entities.append(item)
def place_entities(self, room, entities, max_monsters_per_room, max_items_per_room): # Get a random number of monsters number_of_monsters = randint(0, max_monsters_per_room) number_of_items = randint(0, max_items_per_room) for i in range(number_of_monsters): # get those monsters in # Choose a random location in the room x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): if randint(0, 100) < 80: fighter_component = Fighter(hp=10, defense=0, power=3) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.desaturated_green, 'Orc', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) else: fighter_component = Fighter(hp=16, defense=1, power=4) ai_component = BasicMonster() monster = Entity(x, y, 'T', libtcod.darker_green, 'Troll', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) entities.append(monster) for i in range(number_of_items): x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): item_component = Item() item = Entity(x, y, '!', libtcod.violet, 'Healing Potion', render_order=RenderOrder.ITEM, item=item_component) entities.append(item)
def get_game_variables(constants): fighter_component = Fighter(hp=100, defense=1, power=2, magic=0, magic_defense=1, talismanhp=0, gold=0) inventory_component = Inventory(26) equipment_inventory_component = Inventory(26) level_component = Level() equipment_component = Equipment() player = Entity(0, 0, '@', libtcod.white, 'Player', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, inventory=inventory_component, level=level_component, equipment=equipment_component, equipment_inventory=equipment_inventory_component) entities = [player] gold_value = 1 equipment_component = Equippable(EquipmentSlots.MAIN_HAND, power_bonus=1, gold=gold_value) dagger = Entity(0, 0, '-', libtcod.darker_orange, "Terrium Dagger (+1 atk)", equippable=equipment_component) player.equipment_inventory.add_item(dagger) player.equipment.toggle_equip(dagger) gold_value = 2 item_component = Item(use_function=cast_magic, damage=2, maximum_range=3, gold=gold_value) magic_wand = Entity(0, 0, '|', libtcod.darker_sepia, "Magic Wand", item=item_component) player.inventory.add_item(magic_wand) game_map = GameMap(constants['map_width'], constants['map_height']) game_map.make_map(constants['max_rooms'], constants['room_min_size'], constants['room_max_size'], constants['map_width'], constants['map_height'], player, entities) message_log = MessageLog(constants['message_x'], constants['message_width'], constants['message_height']) game_state = GameStates.PLAYERS_TURN return player, entities, game_map, message_log, game_state
def place_entities(self, room, entities): # [NUMBER OF ITEMS/MONSTERS PER ROOM, DUNGEON LEVEL] max_monsters_per_room = from_dungeon_level([[2, 1], [3, 4], [5, 6]], self.dungeon_level) max_items_per_room = from_dungeon_level([[10, 1], [2, 4]], self.dungeon_level) # Get a random number of monsters number_of_monsters = randint(0, max_monsters_per_room) # Get a random number of items number_of_items = randint(0, max_items_per_room) # [CHANCE OF SPAWNING, DUNGEON LEVEL] monster_chances = { 'ragged_sailor': 60, 'skeleton': from_dungeon_level([[30, 1], [40, 2], [50, 3]], self.dungeon_level), 'troll': from_dungeon_level([[15, 1], [30, 2], [60, 3]], self.dungeon_level) } item_chances = { 'healing_potion': 35, 'rapier': from_dungeon_level([[5, 1]], self.dungeon_level), 'buckler': from_dungeon_level([[15, 1]], self.dungeon_level), 'fancy_hat': from_dungeon_level([[5, 1]], self.dungeon_level), 'fancy_shirt': from_dungeon_level([[5, 1]], self.dungeon_level), 'lightning_scroll': from_dungeon_level([[25, 1]], self.dungeon_level), 'fireball_scroll': from_dungeon_level([[25, 1]], self.dungeon_level), 'confusion_scroll': from_dungeon_level([[10, 1]], self.dungeon_level), 'flintlock': from_dungeon_level([[50, 1]], self.dungeon_level) } for i in range(number_of_monsters): #Choose a random location in the room x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) # Check if an entity is already at that lockation if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): monster_choice = random_choice_from_dict(monster_chances) if monster_choice == 'ragged_sailor': fighter_component = Fighter(hp=15, defense=1, power=4, xp=35) ai_component = BasicMonster() monster = Entity(x, y, 's', libtcod.desaturated_green, 'Ragged Sailor', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) elif monster_choice == 'skeleton': fighter_component = Fighter(hp=20, defense=3, power=4, xp=100) ai_component = BasicMonster() monster = Entity(x, y, 'k', libtcod.darker_green, 'Skeleton', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) else: fighter_component = Fighter(hp=30, defense=4, power=8, xp=100) ai_component = BasicMonster() monster = Entity(x, y, 'T', libtcod.darker_green, 'Troll', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) entities.append(monster) for i in range(number_of_items): x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): item_choice = random_choice_from_dict(item_chances) ## ADD SOME ITEMS HERE FOR FUN if item_choice == 'healing_potion': item_component = Item(use_function=heal, amount=40) item = Entity(x, y, '!', libtcod.violet, 'Healing Potion', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'rapier': equippable_component = Equippable(EquipmentSlots.MAIN_HAND, power_bonus=3) item = Entity(x, y, '/', libtcod.sky, 'Rapier', equippable=equippable_component) elif item_choice == 'buckler': equippable_component = Equippable(EquipmentSlots.OFF_HAND, defense_bonus=1) item = Entity(x, y, '[', libtcod.darker_orange, 'Buckler', equippable=equippable_component) elif item_choice == 'fancy_hat': equippable_component = Equippable(EquipmentSlots.HEAD, defense_bonus=1) item = Entity(x, y, '^', libtcod.crimson, 'Fancy Hat', equippable=equippable_component) elif item_choice == 'fancy_shirt': equippable_component = Equippable(EquipmentSlots.TORSO, defense_bonus=1) item = Entity(x, y, ';', libtcod.crimson, 'Fancy Shirt', equippable=equippable_component) elif item_choice == 'fireball_scroll': item_component = Item( use_function=cast_fireball, targeting=True, targeting_message=Message( 'Left-click a target for the fireball, or right-click to cancel.', libtcod.light_cyan), damage=25, radius=3) item = Entity(x, y, '#', libtcod.red, 'Fireball Scroll', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'confusion_scroll': item_component = Item( use_function=cast_confuse, targeting=True, targeting_message=Message( 'Left-click an enemy to confuse it, or right-click to cancel.', libtcod.light_cyan)) item = Entity(x, y, '#', libtcod.light_pink, 'Confusion Scroll', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'flintlock': item_component = Item( use_function=cast_bullet, targeting=True, targeting_message=Message( 'Left-click an enemy to shoot it, or right-click to cancel.', libtcod.light_cyan), damage=40, maximum_range=5) item = Entity(x, y, '+', libtcod.light_pink, 'Flintlock', render_order=RenderOrder.ITEM, item=item_component) else: item_component = Item( use_function=cast_lightning, targeting=True, targeting_message=Message( 'Left-click an enemy to lightning strike it, or right-click to cancel.', libtcod.light_cyan), damage=40, maximum_range=5) item = Entity(x, y, '#', libtcod.yellow, 'Lightning Scroll', render_order=RenderOrder.ITEM, item=item_component) entities.append(item)
def get_game_variables(constants): fighter_component = Fighter(hp=100, defense=1, power=2, magic=0, magic_defense=1, talismanhp=0, gold=0, status=None, mana=100) inventory_component = Inventory(26) equipment_inventory_component = Inventory(26) level_component = Level() equipment_component = Equipment() player = Entity(0, 0, constants['player_overworld_tile'], libtcod.white, 'Player', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, inventory=inventory_component, level=level_component, equipment=equipment_component, equipment_inventory=equipment_inventory_component) entities = [player] equipment_component = Equippable(EquipmentSlots.MAIN_HAND, power_bonus=1, gold=1) dagger = Entity(0, 0, constants['dagger_tile'], libtcod.white, "Terrium Dagger (+1 atk)", equippable=equipment_component) player.equipment_inventory.add_item(dagger) player.equipment.toggle_equip(dagger) item_component = Item(use_function=cast_magic, damage=2, maximum_range=3, gold=2) magic_wand = Entity(0, 0, constants['magic_wand_tile'], libtcod.white, "Magic Wand", item=item_component) player.inventory.add_item(magic_wand) game_map = GameMap(constants['map_width'], constants['map_height']) game_map.make_map( constants['max_rooms'], constants['room_min_size'], constants['room_max_size'], constants['map_width'], constants['map_height'], player, entities, constants['orc_tile'], constants['healing_potion_tile'], constants['scroll_tile'], constants['troll_tile'], constants['stairs_tile'], constants['sword_tile'], constants['shield_tile'], constants['dagger_tile'], constants['magic_wand_tile'], constants['greater_healing_potion_tile'], constants['ghost_tile'], constants['slime_tile'], constants['corpse_tile'], constants['goblin_tile'], constants['baby_slime_tile'], constants['skeleton_tile'], constants['slime_corpse_tile'], constants['baby_slime_corpse_tile'], constants['skeleton_corpse_tile'], constants['mana_potion_tile'], constants['wizard_staff_tile'], constants['health_talisman_tile'], constants['basilisk_tile'], constants['treasure_tile'], constants['chestplate_tile'], constants['leg_armor_tile'], constants['helmet_tile'], constants['amulet_tile'], constants['floor_tile'], constants['long_bow_tile'], constants['arrow_tile'], constants['wall_tile'], constants['grass_tile'], constants['path_tile'], constants['roof_tile'], constants['brick_tile'], constants['player_overworld_tile'], constants['player_tile'], constants['forest_tile'], constants['door_tile'], constants['sign_tile']) item_descriptors = [ 'Valor', 'Power', 'Ingenuity', 'Glory', 'Strength', 'Speed', 'Wealth', 'Divinity', 'Energy', 'Honor', 'Resistance', 'Greatness', 'Courage', 'Intelligence' ] all_shop_items = [] item_component = Item(use_function=heal, amount=20, gold=20) item = Entity(0, 0, constants['healing_potion_tile'], libtcod.white, "Health Potion (+20 HP)", render_order=RenderOrder.ITEM, item=item_component) all_shop_items.append(item) item_component = Item(use_function=recover_mana, amount=20, gold=10) item = Entity(0, 0, constants['mana_potion_tile'], libtcod.white, "Mana Potion (+20 MANA)", render_order=RenderOrder.ITEM, item=item_component) all_shop_items.append(item) all_shop_equipment = [] sword_amount = randint(2, 4) equippable_component = Equippable(EquipmentSlots.MAIN_HAND, power_bonus=sword_amount, gold=10) item = Entity(0, 0, constants['sword_tile'], libtcod.white, "Terrium Sword of " + random.choice(item_descriptors) + " (+" + str(sword_amount) + " atk)", equippable=equippable_component) all_shop_equipment.append(item) shield_amount = randint(1, 2) equippable_component = Equippable(EquipmentSlots.OFF_HAND, defense_bonus=shield_amount, gold=7) item = Entity(0, 0, constants['shield_tile'], libtcod.white, "Terrium Shield of " + random.choice(item_descriptors) + " (+" + str(shield_amount) + " def)", equippable=equippable_component) all_shop_equipment.append(item) chestplate_amount = randint(2, 3) equippable_component = Equippable(EquipmentSlots.CHEST, defense_bonus=chestplate_amount, gold=20) item = Entity(0, 0, constants['chestplate_tile'], libtcod.darker_grey, "Terrium Chestplate of " + random.choice(item_descriptors) + " (+" + str(chestplate_amount) + " def)", equippable=equippable_component) all_shop_equipment.append(item) leg_amount = randint(1, 3) equippable_component = Equippable(EquipmentSlots.LEGS, defense_bonus=leg_amount, gold=15) item = Entity(0, 0, constants['leg_armor_tile'], libtcod.darker_grey, "Terrium Leg Armor of " + random.choice(item_descriptors) + " (+" + str(leg_amount) + " def)", equippable=equippable_component) all_shop_equipment.append(item) helmet_amount = randint(1, 2) equippable_component = Equippable(EquipmentSlots.HEAD, defense_bonus=helmet_amount, gold=5) item = Entity(0, 0, constants['helmet_tile'], libtcod.darker_grey, "Terrium Helmet of " + random.choice(item_descriptors) + " (+" + str(helmet_amount) + " def)", equippable=equippable_component) all_shop_equipment.append(item) amulet_amount = randint(1, 4) equippable_component = Equippable(EquipmentSlots.AMULET, magic_bonus=amulet_amount, gold=6) item = Entity(0, 0, constants['amulet_tile'], libtcod.darker_grey, "Terrium Amulet of " + random.choice(item_descriptors) + " (+" + str(amulet_amount) + " mgk)", equippable=equippable_component) all_shop_equipment.append(item) number_of_shop_items = randint(1, 3) for i in range(number_of_shop_items): random_item = randint(0, len(all_shop_items) - 1) game_map.shop_items.append(all_shop_items[random_item]) number_of_shop_equipment = randint(1, 2) for i in range(number_of_shop_equipment): random_equipment = randint(0, len(all_shop_equipment) - 1) game_map.shop_equipment_items.append( all_shop_equipment[random_equipment]) message_log = MessageLog(constants['message_x'], constants['message_width'], constants['message_height']) game_state = GameStates.PLAYERS_TURN return player, entities, game_map, message_log, game_state
def place_entities(self, entities, max_monsters_per_room, max_items_per_room): # Get a random number of monsters number_of_monsters = randint(0, max_monsters_per_room) number_of_items = randint(0, max_items_per_room) for _ in range(number_of_monsters): # Choose a random location in the room # radius of 1 because enemies will just walk around anyway (x, y) = self.find_spawn(1) if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): if randint(0, 100) < 50: fighter_comp = Fighter(hp=10, defense=0, power=3) ai_comp = BasicMonster() monster = Entity(x, y, 'Bobcat', 'bobcat', 'bones', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_comp, ai=ai_comp) else: fighter_comp = Fighter(hp=16, defense=1, power=4) ai_comp = BasicMonster() monster = Entity(x, y, 'Wolf', 'wolf', 'bones', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_comp, ai=ai_comp) entities.append(monster) for _ in range(number_of_items): x, y = self.find_spawn(1) if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): item_chance = randint(0, 100) if item_chance < 70: item_component = Item(use_function=heal, amount=4) item = Entity(x, y, 'Healing Potion', 'healing_potion', render_order=RenderOrder.ITEM, item=item_component) entities.append(item) elif item_chance < 80: item_component = Item( use_function=cast_fireball, targeting=True, targeting_message=Message( 'Left-click a target tile for the fireball, or right-click to cancel.', pygame.Color('cyan')), damage=12, radius=3) item = Entity(x, y, 'Fireball Scroll', 'fireball_scroll', render_order=RenderOrder.ITEM, item=item_component) entities.append(item) elif item_chance < 90: item_component = Item( use_function=cast_confuse, targeting=True, targeting_message=Message( 'Left-click an enemy to confuse it, or right-click to cancel.', pygame.Color('cyan'))) item = Entity(x, y, 'Confusion Scroll', 'confusion_scroll', render_order=RenderOrder.ITEM, item=item_component) entities.append(item) else: item_component = Item(use_function=cast_lightning, damage=20, maximum_range=5) item = Entity(x, y, 'Lightning Scroll', 'lightning_scroll', render_order=RenderOrder.ITEM, item=item_component) entities.append(item)
def init_new_game(self, params): choice = params self.player = None self.levels = None self.time_counter = None # Create player inventory_component = Inventory(26) f_data = self.data.fighters["player"] fighter_component = Fighter(hp=f_data["hp"], ac=f_data["ac"], ev=f_data["ev"], power=f_data["power"], mv_spd=f_data["mv_spd"], atk_spd=f_data["atk_spd"], size=f_data["size"], fov=f_data["fov"]) light_component = LightSource(radius=fighter_component.fov) player_component = Player(50) abilities_component = Abilities("player") status_effects_component = StatusEffects("player") summoner_component = Summoner() player = Entity(1, 1, 3, player_component.char["player"], "default", "player", blocks=True, player=player_component, fighter=fighter_component, inventory=inventory_component, light_source=light_component, summoner=summoner_component, indicator_color="gray", abilities=abilities_component, status_effects=status_effects_component, stand_on_messages=False) player.player.avatar["player"] = fighter_component avatar_f_data = self.data.fighters[choice] a_fighter_component = Fighter(hp=avatar_f_data["hp"], ac=avatar_f_data["ac"], ev=avatar_f_data["ev"], power=avatar_f_data["power"], mv_spd=avatar_f_data["mv_spd"], atk_spd=avatar_f_data["atk_spd"], size=avatar_f_data["size"], fov=avatar_f_data["fov"]) player.player.avatar[choice] = a_fighter_component player.player.avatar[choice].owner = player player.abilities.initialize_abilities(choice) player.player.char[choice] = tilemap()["monsters"][choice] player.player.char_exp[choice] = 20 player.player.avatar[choice].max_hp += 20 player.player.avatar[choice].hp += 20 player.player.avatar[choice].power += 1 player.player.insights = 200 self.player = player character_menu = MenuData(name="avatar_info", params=self.player) self.menus.create_or_show_menu(character_menu) message_log = MessageLog(4) self.message_log = message_log self.message_log.owner = self # Initialize game camera game_camera = Camera(1, 1, self.ui.viewport.w, self.ui.viewport.h, self.options) self.game_camera = game_camera self.game_camera.owner = self levels = Levels(tileset=self.options.gfx) self.levels = levels self.levels.owner = self blt.clear_area(2, self.ui.viewport.offset_h + self.ui.offset_y + 1, self.ui.viewport.x, 1) # if settings.gfx == "ascii": # player.char = tilemap()["player"] # player.color = "lightest green" self.levels.change("hub") self.fov_recompute = True self.game_state = GameStates.PLAYER_TURN self.time_counter = self.TimeCounter(owner=self)
def get_fighter(self, level): return Fighter(hp=self.__get_hp(level), defense=self.__get_defense(level), power=self.__get_power(level))
def main(): screen_width = 80 # /4 = 20 screen_height = 50 # /4 ~= 12 # Map panel parameters map_width = 45 map_height = 40 fov_algorithm = libtcod.FOV_SHADOW fov_light_walls = True fov_radius = 9 # Health/Stats panel parameters bar_x = 4 bar_width = 24 panel_height = screen_height - map_height - 1 panel_y = screen_height - panel_height # Message panel parameters message_x = bar_width + bar_x + 2 message_width = screen_width - bar_width - bar_x - 2 message_height = panel_height - 2 message_log = MessageLog(message_x, message_width, message_height) # set up player entity and active entity list # TODO: Allow player to assign stats when starting to play fighter_component = Fighter( hp=30, defense=5, spdefense=5, attack=5, spattack=5, speed=5) player = Entity(int(screen_width / 2), int(screen_height / 2), '@', libtcod.white, 'Player', render_order=RenderOrder.ACTOR, blocks=True, fighter=fighter_component) entities = [] # set up console libtcod.console_set_custom_font('arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'libtcod tutorial revised', False, libtcod.RENDERER_SDL2, vsync=True) # set up all panels con = libtcod.console.Console(screen_width, screen_height) panel = libtcod.console.Console(screen_width, panel_height) # load map, entities and player game_world = GameWorld(map_width, map_height) game_world.loadfirstfloor(player, entities) # player field of vision variables fov_recompute = True fov_map = initialize_fov(game_world.currmap) # input variables key = libtcod.Key() mouse = libtcod.Mouse() # state variables game_state = GameState.PLAYERS_TURN while not libtcod.console_is_window_closed(): # poll input libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) # compute field of vision if fov_recompute: if game_world.currmap.islair: current_fov_radius = 20 else: current_fov_radius = fov_radius recompute_fov(fov_map, player.x, player.y, current_fov_radius, fov_light_walls, fov_algorithm) # draw screen render_all(con, panel, entities, player, game_world.currmap, message_log, fov_map, fov_recompute, screen_width, screen_height, bar_x, bar_width, panel_height, panel_y, mouse) fov_recompute = False libtcod.console_flush() # erase previous player position clear_all(con, entities) # parse input action = handle_keys(key) move = action.get('move') exit = action.get('exit') fullscreen = action.get('fullscreen') confirm = action.get('confirm') cancel = action.get('cancel') wait = action.get('wait') player_turn_results = [] # update if move and game_state == GameState.PLAYERS_TURN: dx, dy = move # saves dx and dy outside of the while loop too dest_x = player.x + dx dest_y = player.y + dy if not game_world.currmap.tileblocked(dest_x, dest_y): target = get_blocking_entities_at_location( entities, dest_x, dest_y) if target: if target.door: game_world.movetonextroom(player, entities, target.door.direction) fov_map = initialize_fov(game_world.currmap) fov_recompute = True con.clear(fg=(0, 0, 0)) elif target.stairs: game_world.movetonextfloor(player, entities) fov_map = initialize_fov(game_world.currmap) fov_recompute = True con.clear(fg=(0, 0, 0)) elif target.fighter: attack_results = player.fighter.attacktarget( target, player.fighter.attacks[0]) player_turn_results.extend(attack_results) else: player.move(dx, dy) fov_recompute = True if (game_state == GameState.PLAYERS_TURN): game_state = GameState.ENEMY_TURN if wait and game_state == GameState.PLAYERS_TURN: game_state = GameState.ENEMY_TURN if exit: return True if fullscreen: libtcod.console_set_fullscreen( not libtcod.console_is_fullscreen()) for player_turn_result in player_turn_results: message = player_turn_result.get('message') dead_entity = player_turn_result.get('dead') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: if (dead_entity.char == '@'): # dead boss, spawn stairs, update world game_world.bosses_cleared[game_world.current_floor] = True entities.extend( game_world.currmap.spawnstairsdown()) message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GameState.ENEMY_TURN: for entity in entities: if entity.ai: enemy_turn_results = entity.ai.take_turn( game_world.currmap, entities) for enemy_turn_result in enemy_turn_results: message = enemy_turn_result.get('message') dead_entity = enemy_turn_result.get('dead') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: if (dead_entity.char == '@'): # dead boss, spawn stairs, update world game_world.bosses_cleared[game_world.current_floor] = True entities.extend( game_world.currmap.spawnstairsdown()) message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GameState.PLAYER_DEAD: break if game_state == GameState.PLAYER_DEAD: break else: game_state = GameState.PLAYERS_TURN
from components.ai import HostileEnemy from components import consumable, equippable from components.equipment import Equipment from components.fighter import Fighter from components.inventory import Inventory from components.level import Level from entity import Actor, Item player = Actor( char="@", color=(255, 255, 255), name="Player", ai_cls=HostileEnemy, equipment=Equipment(), fighter=Fighter(hp=30, base_defense=1, base_power=2), inventory=Inventory(capacity=26), level=Level(level_up_base=200), ) orc = Actor( char="o", color=(63, 127, 63), name="Orc", ai_cls=HostileEnemy, equipment=Equipment(), fighter=Fighter(hp=10, base_defense=0, base_power=3), inventory=Inventory(capacity=0), level=Level(xp_given=35), ) troll = Actor( char="T",
def main(): screen_width = 80 screen_height = 50 bar_width = 20 panel_height = 7 panel_y = screen_height - panel_height message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 map_width = 80 map_height = 43 room_max_size = 10 room_min_size = 6 max_rooms = 30 fov_algorithm = 0 fov_light_walls = True fov_radius = 10 max_monsters_per_room = 3 max_items_per_room = 2 colors = { 'dark_wall': libtcod.Color(0, 0, 100), 'dark_ground': libtcod.Color(50, 50, 150), 'light_wall': libtcod.Color(130, 110, 50), 'light_ground': libtcod.Color(200, 180, 50) } fighter_component = Fighter(hp=30, defense=2, power=5) inventory_component = Inventory(26) player = Entity(0, 0, '@', libtcod.white, "Player", blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, inventory=inventory_component) entities = [player] libtcod.console_set_custom_font( 'arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'libtcod tutorial revised', False) con = libtcod.console_new(screen_width, screen_height) panel = libtcod.console_new(screen_width, panel_height) game_map = GameMap(map_width, map_height) game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room, max_items_per_room) fov_recompute = True fov_map = initialize_fov(game_map) message_log = MessageLog(message_x, message_width, message_height) key = libtcod.Key() mouse = libtcod.Mouse() game_state = GameStates.PLAYERS_TURN previous_game_state = game_state targeting_item = None while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) if fov_recompute: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) render_all(con, panel, entities, player, game_map, fov_map, fov_recompute, message_log, screen_width, screen_height, bar_width, panel_height, panel_y, mouse, colors, game_state) libtcod.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) move = action.get('move') pickup = action.get('pickup') show_inventory = action.get('show_inventory') drop_inventory = action.get('drop_inventory') inventory_index = action.get('inventory_index') exit = action.get('exit') fullscreen = action.get('fullscreen') left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') player_turn_results = [] if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if not game_map.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location( entities, destination_x, destination_y) if target: attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: player.move(dx, dy) fov_recompute = True game_state = GameStates.ENEMY_TURN elif pickup and game_state == GameStates.PLAYERS_TURN: for entity in entities: if entity.item and entity.x == player.x and entity.y == player.y: pickup_results = player.inventory.add_item(entity) player_turn_results.extend(pickup_results) break else: message_log.add_message( Message('There is nothing here to pick up.', libtcod.yellow)) if show_inventory: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY if drop_inventory: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY if inventory_index is not None and previous_game_state != GameStates.PLAYER_DEAD and inventory_index < len( player.inventory.items): item = player.inventory.items[inventory_index] if game_state == GameStates.SHOW_INVENTORY: player_turn_results.extend( player.inventory.use(item, entities=entities, fov_map=fov_map)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) if game_state == GameStates.TARGETING: if left_click: target_x, target_y = left_click item_use_results = player.inventory.use(targeting_item, entities=entities, fov_map=fov_map, target_x=target_x, target_y=target_y) player_turn_results.extend(item_use_results) elif right_click: player_turn_results.append({'targeting_cancelled': True}) if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: return True if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) for player_turn_result in player_turn_results: message = player_turn_result.get('message') dead_entity = player_turn_result.get('dead') item_added = player_turn_result.get('item_added') item_consumed = player_turn_result.get('consumed') item_dropped = player_turn_result.get('item_dropped') targeting = player_turn_result.get('targeting') targeting_cancelled = player_turn_result.get('targeting_cancelled') if message: message_log.add_message(message) if targeting_cancelled: game_state = previous_game_state message_log.add_message(Message('Targeting cancelled')) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN if item_consumed: game_state = GameStates.ENEMY_TURN if targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities) for enemy_turn_result in enemy_turn_results: message = enemy_turn_result.get('message') dead_entity = enemy_turn_result.get('dead') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break else: game_state = GameStates.PLAYERS_TURN
def place_entities(self, room, entities): # 部屋のオブジェクト数の決定 max_monsters_per_room = from_dungeon_level( [[2, 1], [3, 4], [5, 6], [6, 12]], self.dungeon_level) max_items_per_room = from_dungeon_level([[1, 1], [2, 6]], self.dungeon_level) number_of_monsters = randint(0, max_monsters_per_room) number_of_items = randint(0, max_items_per_room) # [確率,発生する階数] monster_chances = { 'goblin': from_dungeon_level([[80, 1], [60, 7], [30, 10], [0, 14]], self.dungeon_level), 'troll': from_dungeon_level([[15, 3], [60, 5], [80, 14]], self.dungeon_level), 'ogre': from_dungeon_level([[15, 6], [30, 10], [60, 14]], self.dungeon_level) } item_chances = { 'healing_potion': 15, 'bronze_sword': from_dungeon_level([[5, 4]], self.dungeon_level), 'shield': from_dungeon_level([[5, 6]], self.dungeon_level), 'iron_sword': from_dungeon_level([[5, 8]], self.dungeon_level), 'lightning_scroll': from_dungeon_level([[25, 4], [40, 8]], self.dungeon_level), 'fireball_scroll': from_dungeon_level([[25, 6], [40, 10]], self.dungeon_level), 'confusion_scroll': from_dungeon_level([[10, 2], [20, 4]], self.dungeon_level) } # モンスターの数だけ実行 for i in range(number_of_monsters): # 部屋のランダムな位置を取得 x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) # 得られた座標に既にEntitiyが存在しないならば if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): monster_choice = random_choice_from_dict(monster_chances) if monster_choice == 'goblin': fighter_component = Fighter(hp=25, defense=0, power=3, xp=35) ai_component = BasicMonster() monster = Entity(x, y, 'g', libtcod.desaturated_green, 'goblin', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) elif monster_choice == 'troll': fighter_component = Fighter(hp=40, defense=2, power=4, xp=70) ai_component = BasicMonster() monster = Entity(x, y, 'T', libtcod.darker_green, 'Troll', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR, ai=ai_component) elif monster_choice == 'ogre': fighter_component = Fighter(hp=70, defense=1, power=4, xp=120) ai_component = BasicMonster() equipment_component = Equipment() equippable_component = Equippable(EquipmentSlots.MAIN_HAND, power_daice=2, daice=2, base_power=3) club = Entity(0, 0, 'l', libtcod.sky, 'club', equippable=equippable_component) monster = Entity(x, y, 'O', libtcod.darker_green, 'Ogre', blocks=True, fighter=fighter_component, equipment=equipment_component, render_order=RenderOrder.ACTOR, ai=ai_component) monster.equipment.toggle_equip(club) entities.append(monster) else: i -= 1 # アイテムの数だけ実行 for i in range(number_of_items): x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) # 得られた座標に既にEntitiyが存在しないならば if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): item_choice = random_choice_from_dict(item_chances) if item_choice == 'healing_potion': item_component = Item(use_function=heal, amount=40) item = Entity(x, y, '!', libtcod.violet, 'Healing Potion', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'fireball_scroll': item_component = Item( use_function=cast_fireball, targeting=True, targeting_message=Message( 'Left-click a target tile for the fireball, or right-click to cancel.', libtcod.light_cyan), damage=25, radius=3) item = Entity(x, y, '#', libtcod.red, 'Fireball Scroll', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'confusion_scroll': item_component = Item( use_function=cast_confuse, targeting=True, targeting_message=Message( 'Left-click an enemy to confuse it, or right-click to cancel.', libtcod.light_cyan)) item = Entity(x, y, '#', libtcod.light_pink, 'Confusion Scroll', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'bronze_sword': equippable_component = Equippable( EquipmentSlots.MAIN_HAND, power_daice=2, daice=3, base_power=1) item = Entity(x, y, '/', libtcod.sky, 'Bronze Sword', equippable=equippable_component) elif item_choice == 'shield': equippable_component = Equippable( EquipmentSlots.OFF_HAND, defense_bonus=1) item = Entity(x, y, '[', libtcod.darker_orange, 'Shield', equippable=equippable_component) elif item_choice == 'iron_sword': equippable_component = Equippable( EquipmentSlots.MAIN_HAND, power_daice=4, daice=3, base_power=2) item = Entity(x, y, '/', libtcod.sky, 'Iron Sword', equippable=equippable_component) else: item_component = Item(use_function=cast_lightning, damage=40, maximum_range=5) item = Entity(x, y, '#', libtcod.yellow, 'Lightning Scroll', render_order=RenderOrder.ITEM, item=item_component) entities.append(item) else: i -= 1
def main(): # Initiate important variables screen_width = 80 screen_height = 50 bar_width = 20 panel_height = 7 panel_y = screen_height - panel_height message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 map_width = 80 map_height = 43 room_max_size = 10 room_min_size = 6 max_rooms = 30 fov_algorithm = 0 fov_light_walls = True fov_radius = 10 max_monsters_per_room = 3 max_items_per_room = 2 colors = { 'dark_wall': libtcod.Color(0, 0, 100), 'dark_ground': libtcod.Color(50, 50, 150), 'light_wall': libtcod.Color(130, 110, 50), 'light_ground': libtcod.Color(200, 180, 50), } # Initiate the objects that will be important in rendering and the map fighter_component = Fighter(hp=30, defense=2, power=5) inventory_component = Inventory(26) player = Entity(0, 0, '@', libtcod.white, 'Player', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, inventory=inventory_component) entities = [player] libtcod.console_set_custom_font('arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'Cardinal Code', False) #boolean is fullscreen or not con = libtcod.console_new(screen_width, screen_height) panel = libtcod.console_new(screen_width, panel_height) game_map = GameMap(map_width, map_height) game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room, max_items_per_room) fov_recompute = True fov_map = initialize_fov(game_map) message_log = MessageLog(message_x, message_width, message_height) key = libtcod.Key() mouse = libtcod.Mouse() game_state = GameStates.PLAYERS_TURN # Main game loop while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) # fov_recompute tells if the render function should recompute the FOV # recompute_fov will recompute the FOV from render_functions.py based on the initialized variables if(fov_recompute): recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) # Renders the map and the screens render_all(con, panel, entities, player, game_map, fov_map, fov_recompute, message_log, screen_width, screen_height, bar_width, panel_height, panel_y, mouse, colors) libtcod.console_flush() # Clears entities whose position changed clear_all(con, entities) # Get what key was pressed, from sets of dictionaries action = handle_keys(key) # Then get the action from the sets of dictionaries established in input_handlers.py move = action.get('move') pickup = action.get('pickup') exit = action.get('exit') fullscreen = action.get('fullscreen') player_turn_results = [] # If move has a value and the game_state is the player's state if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy # If the player's destination is not blocked, do something if not game_map.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location(entities, destination_x, destination_y) # If there is an entity at the destination, do this if target: player.fighter.attack(target) attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: player.move(dx, dy) fov_recompute = True game_state = GameStates.ENEMY_TURN elif pickup and game_state == GameStates.PLAYERS_TURN: for entity in entities: if entity.item and entity.x == player.x and entity.y == player.y: pickup_results = player.inventory.add_item(entity) player_turn_results.extend(pickup_results) break else: message_log.add_message(Message('There is nothing here to pickup.', libtcod.yellow)) if exit: return True if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen) for player_turn_result in player_turn_results: message = player_turn_result.get('message') dead_entity = player_turn_result.get('dead') item_added = player_turn_result.get('item_added') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: entity.ai.take_turn(player, fov_map, game_map, entities) enemy_turn_results = entity.ai.take_turn(player,fov_map, game_map, entities) for enemy_turn_result in enemy_turn_results: message = enemy_turn_result.get('message') dead_entity = enemy_turn_result.get('dead') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break else: game_state = GameStates.PLAYERS_TURN