def draw_mouse_over_info(self, surface, game_data, gfx_data): mx, my = pygame.mouse.get_pos() if self.health_bar.is_inside(mx, my): display_text( surface, "This is how much health you have", Assets.get().font_message, (mx, my), ) elif self.shield_bar.is_inside(mx, my): display_text( surface, "This is how much shield you have", Assets.get().font_message, (mx, my), ) for fm in self.formula_markers: if fm.is_inside(mx, my): display_text(surface, "A formula", Assets.get().font_message, (mx, my)) return for cm in self.consumable_markers: if cm.is_inside(mx, my): item = game_data.inventory.get_quickslot(cm.consumable_index) if item: display_text( gfx_data.main, item.DESCRIPTION, Assets.get().font_message, (mx, my), ) else: display_text( gfx_data.main, "No item equipped", Assets.get().font_message, (mx, my), ) return
def print_stats(): Assets.setup(mock=True) level = 1 monsters = get_monsters(level=level) formula_stats = get_formula_stats() results = calculate_results(monsters, formula_stats) for r in results: m, fd, res = r text = "{}, {}, {}".format(m.name, fd["slots"], res) print(text)
def place_decorations(m, chunks): for c in chunks: drawable_component = Drawable(Assets.get().red_carpet["topleft"]) m.tiles[c.x + 1][c.y + 1].decor.append(drawable_component) drawable_component = Drawable(Assets.get().red_carpet["topright"]) m.tiles[c.x + c.width - 2][c.y + 1].decor.append(drawable_component) drawable_component = Drawable(Assets.get().red_carpet["bottomleft"]) m.tiles[c.x + 1][c.y + c.height - 2].decor.append(drawable_component) drawable_component = Drawable(Assets.get().red_carpet["bottomright"]) m.tiles[c.x + c.width - 2][c.y + c.height - 2].decor.append(drawable_component) for x in range(c.x + 2, c.x + c.width - 2): drawable_component = Drawable(Assets.get().red_carpet["top"]) m.tiles[x][c.y + 1].decor.append(drawable_component) drawable_component = Drawable(Assets.get().red_carpet["bottom"]) m.tiles[x][c.y + c.height - 2].decor.append(drawable_component) for y in range(c.y + 2, c.y + c.height - 2): drawable_component = Drawable(Assets.get().red_carpet["left"]) m.tiles[c.x + 1][y].decor.append(drawable_component) drawable_component = Drawable(Assets.get().red_carpet["right"]) m.tiles[c.x + c.width - 2][y].decor.append(drawable_component) for x in range(c.x + 2, c.x + c.width - 2): for y in range(c.y + 2, c.y + c.height - 2): drawable_component = Drawable(Assets.get().red_carpet["center"]) m.tiles[x][y].decor.append(drawable_component)
def draw(self, game_data, gfx_data): surface = pygame.Surface(game_data.constants.right_panel_size.tuple()) surface.fill(colors.BACKGROUND) if len(self.formula_markers) != len(game_data.player.caster.formulas): self.update_formula_markers(game_data.player, start_y=self.formula_label.pos.y + 40) self.health_bar.draw(surface, game_data.player.fighter.hp, game_data.player.fighter.max_hp) if game_data.player.fighter.shield: self.shield_bar.draw( surface, game_data.player.fighter.shield.level, game_data.player.fighter.shield.max_level, ) else: self.shield_bar.draw(surface, 0, 10) if config.conf.keys: if game_data.map.stairs_found or game_data.map.num_keys_found == game_data.map.num_keys_total: text = "Found {}/{} keys".format(game_data.map.num_keys_found, game_data.map.num_keys_total) else: text = "Found {}/? keys".format(game_data.map.num_keys_found) display_text( surface, text, Assets.get().font_message, (10, 105), ) else: display_text( surface, "Level {}".format(game_data.player.level.current_level), Assets.get().font_message, (10, 105), ) if config.conf.keys: self.xp_bar.draw( surface, game_data.player.level.current_xp, game_data.player.level.xp_to_next_level, ) self.formula_label.draw(surface) for idx, fm in enumerate(self.formula_markers): fm.draw(surface, game_data, game_data.player.caster.formulas[idx]) if config.conf.consumables: for cm in self.consumable_markers: cm.draw(surface, game_data, gfx_data) self.helplabel.draw(surface) display_text( surface, "Floor {}".format(game_data.run_planner.current_level_index + 1), Assets.get().font_message, (10, 850), ) gfx_data.main.blit(surface, self.pos.tuple()) self.draw_mouse_over_info(gfx_data.main, game_data, gfx_data)
def get_drawable(self, visible): if visible: if self.block_sight: # wall return Assets.get().light_wall[self.wall_info] else: return Assets.get().light_floor[self.floor_info] elif self.explored: if self.block_sight: # wall return Assets.get().dark_wall[self.wall_info] else: return Assets.get().dark_floor[self.floor_info] else: return None # not in sight nor explored
def add_light(x, y): drawable_component = Drawable(Assets.get().light) light_component = Light(brightness=4) light = Entity( x, y, "Light", render_order=RenderOrder.DECOR, drawable=drawable_component, light=light_component, ) m.entities.append(light)
def __init__(self, godmode): caster_component = Caster(num_slots=3, num_formulas=3) if godmode: fighter_component = Fighter(hp=10, defense=50, power=50) else: fighter_component = Fighter(hp=10, defense=0, power=3) level_component = Level() drawable_component = Drawable(Assets.get().player) super(Player, self).__init__( x=0, y=0, name="You", speed=100, blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, level=level_component, caster=caster_component, drawable=drawable_component, ) self.last_num_explored = None self.moving_towards = None self.godmode = godmode self.ignore_first_click = False
def apply(self, game_data, gfx_data, target): results = [] # create graphcs target_tiles = get_tiles_within(game_data.map, self.area, target) for pos in target_tiles: gfx_data.visuals.add_temporary(pos, pos, lifespan=0.2, asset=Assets.get().spark_effect, wait=0.2) # cause effect targets = [] for e in game_data.map.entities: if e.fighter and e.pos in target_tiles: targets.append(e) effect = EffectBuilder.create( EffectType.DAMAGE, amount=Freezebomb.DAMAGE, dmg_type=DamageType.COLD, rounds=Freezebomb.ROUNDS, caster=game_data.player, ) for t in targets: results.append( {"message": Message(f"Hit {t.name.lower()} with freezebomb, slowed for {Freezebomb.ROUNDS} rounds")} ) results.extend(effect.apply(t)) return results
def place_consumables(m, chunks, consumable_count): def has_consumables_left(): for val in consumable_count.values(): if val > 0: return True def get_consumable(): while True: itemtype = random.choice(list(consumable_count.keys())) if consumable_count[itemtype] > 0: consumable_count[itemtype] -= 1 return itemtype() placed_consumables = [] # not two consumables in the same square while has_consumables_left(): c = random.choice(chunks) occupied = True while occupied: x = random.randint(c.x + 1, c.x + c.width - 2) y = random.randint(c.y + 1, c.y + c.height - 2) occupied = False for ent in m.entities: if ent.pos == Pos(x, y): occupied = True if (x, y) in placed_consumables: occupied = True placed_consumables.append((x, y)) drawable_component = Drawable(Assets.get().consumable) consumable_component = get_consumable() name = consumable_component.name.capitalize() consumable = Entity( x, y, name, render_order=RenderOrder.ITEM, drawable=drawable_component, consumable=consumable_component, ) m.entities.append(consumable)
def show_on_hit(self, dmg): above = Pos(self.owner.pos.x, self.owner.pos.y - 1) text_surface = [Assets.get().font_title.render(str(dmg), True, colors.RED)] VisualEffectSystem.get().add_temporary( self.owner.pos, above, lifespan=0.3, asset=text_surface, color=colors.RED )
def __init__(self, pos, formula_idx, player, size=Size(100, 30)): super().__init__(pos, size, click_mode=ClickMode.LEFT) self.formula_idx = formula_idx self.player = player self.cooldown_bar = Bar( pos, None, colors.COOLDOWN_BAR_FRONT, colors.COOLDOWN_BAR_BACKGROUND, show_numbers=False, ) self.font = Assets.get().font_message
def place_stairs(m, chunks): stairs_component = Stairs(m.dungeon_level + 1) drawable_component = Drawable(Assets.get().stairs) posx = chunks[-1].x + chunks[-1].width // 2 posy = chunks[-1].y + chunks[-1].height // 2 down_stairs = Entity( posx, posy, "Stairs", render_order=RenderOrder.STAIRS, stairs=stairs_component, drawable=drawable_component, ) m.entities.append(down_stairs)
def __init__(self, pos, text, size, font=None, parent=None, click_mode=ClickMode.LEFT): super().__init__(pos, size, parent=parent, click_mode=click_mode) self.text = text self.font = font if font else Assets.get().font_title
def apply(target): target.fighter.shield = Shield(level, strikebacks, target, distance) target.fighter.shield.visual_effect = VisualEffectSystem.get( ).add_attached( target, Assets.get().shield_effect, target.fighter.shield.color, transform=rotation_transform(), ) return []
def __init__(self, levels, player, constants, timesystem, run_tutorial): self.parts = levels // 3 self.level_count = levels + 1 self.levels = [] self.player = player self.assets = Assets.get() self.constants = constants self.size = constants.map_size self.timesystem = timesystem self.current_level_index = None self.gen_level_idx = 0 self.run_tutorial = run_tutorial
def draw(self, surface, current_value, max_value): display_bar( surface, Assets.get(), self.pos, self.size.width, current_value, max_value, self.color, self.bgcolor, text=self.text, show_numbers=self.show_numbers, )
def place_stairs(game_map, stairs_data): x = stairs_data["x"] y = stairs_data["y"] stairs_component = Stairs(game_map.dungeon_level + 1) drawable_component = Drawable(Assets.get().stairs) stairs = Entity( x, y, "Stairs", render_order=RenderOrder.STAIRS, stairs=stairs_component, drawable=drawable_component, ) return [stairs]
def load_keys(data, game_map): retr = [] assets = Assets.get() for key_data in data["keys"]: drawable_component = Drawable(assets.key) key = Entity( key_data["x"], key_data["y"], "Key", render_order=RenderOrder.ITEM, key=Key(), drawable=drawable_component, ) retr.append(key) game_map.num_keys_total = len(retr) return retr
def apply(target): dmg_amount = amount color = None base = 100 main = 200 if dmg_type == DamageType.FIRE: color = (main, base, base) elif dmg_type == DamageType.COLD: color = (base, base, main) VisualEffectSystem.get().add_temporary( target.pos, target.pos, lifespan=0.2, asset=Assets.get().spark_effect, color=color, wait=0.2, ) return target.fighter.take_damage(source=caster, dmg=dmg_amount, dmg_type=dmg_type)
def __init__(self, constants, parent=None): super().__init__( Pos(0, 0), constants.right_panel_size, visible=False, parent=parent, click_mode=ClickMode.LEFT, ) self.health_bar = Bar(Pos(10, 20), "HP", colors.HP_BAR_FRONT, colors.HP_BAR_BACKGROUND, size=Size(120, 30),) self.shield_bar = Bar( Pos(10, 60), "Shield", colors.SHIELD_BAR_FRONT, colors.SHIELD_BAR_BACKGROUND, size=Size(120, 30), ) self.xp_bar = Bar( Pos(10, 130), text=None, color=colors.XP_BAR_FRONT, bgcolor=colors.XP_BAR_BACKGROUND, size=Size(120, 30), show_numbers=False, ) self.formula_label = Label(Pos(10, 180), "Formulas") self.helplabel = Label(Pos(10, 800), "Help? Tab", font=Assets.get().font_message) self.formula_markers = [] self.setup_consumables(constants.num_quickslots) self.drawing_priority = 2
def place_ingredients(m, chunks, ingredient_count): def has_ingredients_left(): for val in ingredient_count.values(): if val > 0: return True def get_ingredient(): while True: ingredient = random.choice(list(ingredient_count.keys())) if ingredient_count[ingredient] > 0: ingredient_count[ingredient] -= 1 return ingredient placed_ingredients = [] # not two ingredients in the same square while has_ingredients_left(): c = random.choice(chunks) occupied = True while occupied: x = random.randint(c.x + 1, c.x + c.width - 2) y = random.randint(c.y + 1, c.y + c.height - 2) occupied = False for ent in m.entities: if ent.pos == Pos(x, y): occupied = True if (x, y) in placed_ingredients: occupied = True placed_ingredients.append((x, y)) drawable_component = Drawable(Assets.get().ingredient) ingredient_component = get_ingredient() name = ingredient_component.name.capitalize() ingredient = Entity( x, y, f"{name} ingredient", render_order=RenderOrder.ITEM, drawable=drawable_component, ingredient=ingredient_component, ) m.entities.append(ingredient)
def draw(self, game_data, gfx_data): surface = pygame.Surface(game_data.constants.message_log_size.tuple()) surface.fill(colors.BACKGROUND) messages = game_data.log.messages y = 0 start = max( 0, min( len(messages) - self.num_messages, len(messages) - self.num_messages + self.offset, ), ) end = min(len(messages), start + self.num_messages) for idx, msg in enumerate(messages[start:end]): display_text( surface, msg.text, Assets.get().font_message, (50, y + idx * 20), msg.color, ) gfx_data.main.blit(surface, self.pos.tuple())
def place_keys(m, chunks, key_ratio): num_rooms_with_keys = math.floor(len(chunks) * key_ratio) if num_rooms_with_keys > len(chunks[1:-1]): # if it's a map with few rooms num_rooms_with_keys = len(chunks[1:-1]) # sample random rooms but not in the first room, not in the room with stairs rooms_with_keys = random.sample(chunks[1:-1], k=num_rooms_with_keys) placed_keys = [] # not two keys in the same square for _, c in enumerate(rooms_with_keys): occupied = True while occupied: x = random.randint(c.x + 1, c.x + c.width - 2) y = random.randint(c.y + 1, c.y + c.height - 2) occupied = False for cm in c.monsters: if cm.pos == Pos(x, y): occupied = True if (x, y) in placed_keys: occupied = True placed_keys.append((x, y)) drawable_component = Drawable(Assets.get().key) key = Entity(x, y, "Key", render_order=RenderOrder.ITEM, key=Key(), drawable=drawable_component,) m.entities.append(key) m.num_keys_total = num_rooms_with_keys
def draw(self, game_data, gfx_data): if not self.current_lines or self.current_content != self.story_data.current_content: self.current_content = self.story_data.current_content long_lines = self.story_data.current_content.split("\n") lines = [] for current in long_lines: if current.strip() == "": lines.append(current) else: split_lines = textwrap.wrap(current, 60) lines.extend(split_lines) self.current_lines = lines show_lines = self.current_lines[self.offset:self.offset + self.num_lines] display_menu(gfx_data, show_lines, self.size.tuple(), x=20, starty=20) display_text( gfx_data.main, "Press Space to continue", Assets.get().font_message, (350, 750), )
def setup_data_state(constants, run_tutorial=True, previous_data=None): pygame.init() pygame.display.set_caption("Formula") pygame.mixer.quit() pygame.key.set_repeat(100) main = pygame.display.set_mode( (constants.window_size.width, constants.window_size.height)) assets = Assets.setup() godmode = False fps_per_second = 30 story_loader = StoryLoader() story_data = StoryData(story_loader) timesystem = TimeSystem() visuals = VisualEffectSystem.setup(fps_per_second) clock = pygame.time.Clock() windows = WindowManager() rpw = RightPanelWindow(constants) windows.push(rpw) windows.push(GameWindow(constants, parent=rpw)) windows.push(MessageLogWindow(constants, parent=rpw)) windows.push(StoryWindow(constants, story_data, visible=True)) windows.push(StoryHelpWindow(constants)) windows.push(FormulaWindow(constants)) windows.push(FormulaHelpWindow(constants)) windows.push(GeneralHelpWindow(constants)) windows.push(LevelUpWindow(constants)) windows.push(AskQuitWindow(constants)) windows.push(DeadWindow(constants)) windows.push(VictoryWindow(constants)) windows.push(ConsoleWindow(constants)) windows.push(CraftingWindow(constants)) windows.push(CraftingHelpWindow(constants)) windows.push(InventoryWindow(constants)) windows.push(InventoryHelpWindow(constants)) text_width = constants.message_log_text_size.width / get_width( Assets.get().font_message) log = MessageLog(text_width) # for some margin on the sides player = Player(godmode) formula_builder = FormulaBuilder(player.caster.num_slots, player.caster.num_formulas, run_tutorial) levels = 9 planner = RunPlanner(levels, player, constants, timesystem, run_tutorial) fov_map = None ingredient_storage = IngredientStorage() if config.conf.pickupstartcount == "base": ingredient_storage.add_multiple({ Ingredient.FIRE: 2, Ingredient.WATER: 2, Ingredient.EARTH: 2, Ingredient.RANGE: 1, Ingredient.AREA: 1, }) if config.conf.trap: ingredient_storage.add_multiple({ Ingredient.TRAP: 2, }) else: for ing in Ingredient.all(): ingredient_storage.add_multiple( {ing: config.conf.pickupstartcount}) menu_data = AttrDict({"currchoice": 0}) inventory = Inventory(max_count=constants.num_consumables, num_quickslots=constants.num_quickslots) from components.consumable import Firebomb, Freezebomb, Teleporter, CooldownClear # for t in [Firebomb, Freezebomb, Teleporter, CooldownClear, Thingy, Thingmajig]: # inventory.add(t()) #inventory.add(Firebomb()) #inventory.add(Teleporter()) initial_state = GameStates.STORY_SCREEN logger = previous_data.logger if previous_data else BlobLogger() game_data = StateData( player=player, log=log, constants=constants, timesystem=timesystem, fov_map=fov_map, fov_recompute=True, story_data=story_data, run_planner=planner, formula_builder=formula_builder, menu_data=menu_data, ingredient_storage=ingredient_storage, inventory=inventory, logger=logger, initial_state=initial_state, initial_state_history=[GameStates.PLAY], ) camera = Camera(constants.camera_size.width, constants.camera_size.height, game_data) gfx_data = GfxState( main=main, assets=assets, camera=camera, fullscreen=False, visuals=visuals, fps_per_second=fps_per_second, clock=clock, windows=windows, ) if not run_tutorial: game_data.prev_state = [GameStates.FORMULA_SCREEN, GameStates.PLAY] windows.activate_wnd_for_state(game_data.state, game_data, gfx_data) story_data.next_story() # create default formulas Formula.EMPTY, _ = formula_builder.get_empty_formula(caster=player) initial_formulas = formula_builder.evaluate_entity(caster=player) player.caster.set_formulas(initial_formulas) return game_data, gfx_data, initial_state
def __init__(self, pos, consumable_index, size=Size(130, 30)): super().__init__(pos, size, click_mode=ClickMode.LEFT) self.consumable_index = consumable_index self.shortcut = self.get_shortcut(self.consumable_index) self.font = Assets.get().font_message
def get_monster(x, y, game_map, room, monster_choice, entities): assets = Assets.get() def create_pack(hp, defense, power, xp, asset, name): retr = [] packsize = random.randint(1, 3) diffs = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)] clean_diffs = [] for d in diffs: dpos = Pos(x + d[0], y + d[1]) occupied = False if game_map.is_blocked(dpos.x, dpos.y): occupied = True else: for e in entities: if (e.pos == dpos and dpos.x in range(room.x1 + 2, room.x2 - 2) and dpos.y in range(room.y1 + 2, room.y2 - 2)): occupied = True if not occupied: clean_diffs.append(d) if len(clean_diffs) < packsize and len(clean_diffs) < 3: packsize = len(clean_diffs) assert len(clean_diffs) >= packsize for w in range(packsize): diff_idx = random.randint(0, len(clean_diffs) - 1) diff = clean_diffs[diff_idx] wx, wy = x + diff[0], y + diff[1] clean_diffs.remove(diff) fighter_component = Fighter(hp=hp, defense=defense, power=power, xp=xp // packsize) ai = MeleeMonsterAI() drawable_component = Drawable(asset) # randname = "{}-{}".format(name, random.randint(0, 1000)) monster = Monster( wx, wy, name, speed=150, fighter=fighter_component, ai=ai, drawable=drawable_component, ) retr.append(monster) return retr monsters = [] # tutorial if monster_choice == "idiot": fighter_component = Fighter(hp=1, defense=0, power=0, xp=0) ai = DummyMonsterAI() drawable_component = Drawable(assets.thug) monster = Monster( x, y, "Thug", speed=100, fighter=fighter_component, ai=ai, drawable=drawable_component, ) monsters.append(monster) # easy elif monster_choice == "thug": fighter_component = Fighter(hp=15, defense=0, power=3, xp=40) ai = MeleeMonsterAI() drawable_component = Drawable(assets.thug) monster = Monster( x, y, "Thug", speed=100, fighter=fighter_component, ai=ai, drawable=drawable_component, ) monsters.append(monster) elif monster_choice == "axe_thrower": fighter_component = Fighter(hp=10, defense=0, power=1, xp=40) ai = RangedMonsterAI() drawable_component = Drawable(assets.axe_thrower) monster = Monster( x, y, "Axe thrower", speed=100, fighter=fighter_component, ai=ai, drawable=drawable_component, range=5, ) monsters.append(monster) elif monster_choice == "dog_group": monsters.extend( create_pack(hp=5, defense=0, power=1, xp=40, asset=assets.dog, name="Hound")) # medium elif monster_choice == "mercenary": fighter_component = Fighter(hp=25, defense=5, power=5, xp=100) ai = MeleeMonsterAI() drawable_component = Drawable(assets.mercenary) monster = Monster( x, y, "Mercenary", speed=100, fighter=fighter_component, ai=ai, drawable=drawable_component, ) monsters.append(monster) elif monster_choice == "rifleman": fighter_component = Fighter(hp=15, defense=3, power=3, xp=100) ai = RangedMonsterAI() drawable_component = Drawable(assets.rifleman) monster = Monster( x, y, "Rifleman", speed=100, fighter=fighter_component, ai=ai, drawable=drawable_component, range=5, ) monsters.append(monster) elif monster_choice == "boar_group": monsters.extend( create_pack(hp=10, defense=2, power=3, xp=60, asset=assets.boar, name="Boar")) # hard elif monster_choice == "stalker": fighter_component = Fighter(hp=35, defense=5, power=7, xp=200) ai = MeleeMonsterAI() drawable_component = Drawable(assets.stalker) monster = Monster( x, y, "Stalker", speed=100, fighter=fighter_component, ai=ai, drawable=drawable_component, ) monsters.append(monster) elif monster_choice == "zapper": fighter_component = Fighter(hp=20, defense=3, power=3, xp=200) ai = RangedMonsterAI() drawable_component = Drawable(assets.zapper) monster = Monster( x, y, "Zapper", speed=100, fighter=fighter_component, ai=ai, drawable=drawable_component, range=5, ) monsters.append(monster) elif monster_choice == "armored_bear_group": monsters.extend( create_pack( hp=15, defense=4, power=5, xp=200, asset=assets.armored_bear, name="Panzerbear", )) # end of the world as we know it elif monster_choice == "boss": fighter_component = Fighter(hp=150, defense=15, power=8, xp=0) ai = MeleeMonsterAI() drawable_component = Drawable(assets.boss) monster = Monster( x, y, "Arina", speed=150, fighter=fighter_component, ai=ai, drawable=drawable_component, ) monsters.append(monster) else: raise ValueError("Unknown choice: '{}'".format(monster_choice)) assert monsters return monsters
def __init__(self, pos, text, font=None, parent=None): super().__init__(pos, Size(0, 0), parent=parent) self.text = text self.font = font if font else Assets.get().font_title