def complete_quest_option(quest: Quest, boss_npc_type: NpcType, quest_item_type: ItemType, reward_item_id: Callable[[GameState], Optional[ItemId]]) -> DialogOptionData: return DialogOptionData( summary="QUEST: \"%s\"" % quest.name, action_text="give", action=CompleteQuestNpcAction(quest, boss_npc_type, quest_item_type, reward_item_id), ui_icon_sprite=get_item_data_by_type(quest_item_type).icon_sprite, detail_header=get_item_data_by_type(quest_item_type).base_name, detail_body="...")
def generate_loot(self) -> List[LootEntry]: loot = list(self.guaranteed_drops) if random.random() <= self.item_drop_chance: item_level = random.choices(self.item_levels, weights=self.item_level_weights)[0] item_type = random.choice(self.item_types_by_level[item_level]) # TODO control drop rate of uniques vs rares is_unique = get_item_data_by_type(item_type).is_unique if not is_unique and random.random() <= self.item_rare_chance: # TODO determine suffix based on level! suffix_id = random.choice( [suffix_id for suffix_id in ItemSuffixId]) loot.append(SuffixedItemLootEntry(item_type, suffix_id)) else: loot.append(ItemLootEntry(item_type)) if random.random() <= self.consumable_drop_chance: # Warp stone doesn't have a level, but should be dropped across all levels if random.random() < 0.15: consumable_type = ConsumableType.WARP_STONE else: consumable_level = random.choices( self.consumable_levels, weights=self.consumable_level_weights)[0] consumable_type = random.choice( self.consumable_types_by_level[consumable_level]) loot.append(ConsumableLootEntry(consumable_type)) if random.random() <= self.money_drop_chance: amount = random.randint(1, self.level) loot.append(MoneyLootEntry(amount)) return loot
def create_item_on_ground(item_id: ItemId, pos: Tuple[int, int]) -> ItemOnGround: item_type = item_id.item_type entity = WorldEntity(pos, ITEM_ENTITY_SIZE, get_item_data_by_type(item_type).entity_sprite) entity.view_z = 1 # It should be rendered below all other entities return ItemOnGround(entity, item_id)
def _item_types_for_monster_level(monster_level: int, unique: bool) -> Dict[int, List[ItemType]]: d = {} for level in range(max(monster_level - 3, 1), monster_level + 3): items = [item for item in get_items_with_level(level) if get_item_data_by_type(item).is_unique == unique] if items: d[level] = items return d
def give_quest_option(quest: Quest, quest_intro: str, boss_npc_type: NpcType, quest_item_type: ItemType) -> DialogOptionData: return DialogOptionData( summary="QUEST: \"%s\"" % quest.name, action_text="accept quest", action=GiveQuestNpcAction(quest, boss_npc_type, quest_item_type), ui_icon_sprite=get_item_data_by_type(quest_item_type).icon_sprite, detail_header=quest.name, detail_body=quest_intro)
def try_add_item_to_inventory(self, item_id: ItemId) -> bool: item_effect = create_item_effect(item_id) item_type = item_id.item_type item_equipment_category = get_item_data_by_type( item_type).item_equipment_category event = self.game_state.player_state.item_inventory.try_add_item( item_id, item_effect, item_equipment_category) if event is not None: self._handle_item_equip_event(event) return event is not None
def try_add_item_to_inventory(game_state: GameState, item_id: ItemId) -> bool: item_effect = create_item_effect(item_id) item_type = item_id.item_type item_equipment_category = get_item_data_by_type( item_type).item_equipment_category result = game_state.player_state.item_inventory.try_add_item( item_id, item_effect, item_equipment_category) if result: if isinstance(result, ItemWasActivated): item_effect.apply_start_effect(game_state) return result is not None
def _allowed_drop_inside_dungeon(loot_entry: LootEntry): if isinstance(loot_entry, ItemLootEntry): if get_item_data_by_type( loot_entry.item_type ).item_equipment_category == ItemEquipmentCategory.QUEST: # Player has probably completed the quest anyway and there may be several bosses inside the dungeon, so the # ground can get quite crowded return False if isinstance(loot_entry, ConsumableLootEntry): if loot_entry.consumable_type == ConsumableType.WARP_STONE: # Warp stones can't be used inside dungeons, and bosses are guaranteed to drop them return False return True
def sell_item_option(item_id: ItemId, price: int, detail_body: str): item_type = item_id.item_type name_formatter = "{:<13}" cost_formatter = "[{} gold]" sell_prompt = "> " data = get_item_data_by_type(item_type) item_name = build_item_name(item_id) icon_sprite = data.icon_sprite return DialogOptionData( sell_prompt + name_formatter.format(item_name) + cost_formatter.format(price), "sell", BuyItemNpcAction(item_id, price, item_name.lower()), icon_sprite, item_name, detail_body)
def buy_item_option(item_id: ItemId, cost: int): item_type = item_id.item_type data = get_item_data_by_type(item_type) name_formatter = "{:<25}" buy_prompt = "> " cost_formatter = "[{} gold]" item_name = build_item_name(item_id) icon_sprite = data.icon_sprite description_lines = create_item_description(item_id) return DialogOptionData( buy_prompt + name_formatter.format(item_name) + cost_formatter.format(cost), "buy", SellItemNpcAction(cost, item_id, item_name.lower()), icon_sprite, item_name, ", ".join([line.text for line in description_lines]))
def print_loot(): for level in range(1, 10): consumable_types = get_consumables_with_level(level) item_types = get_items_with_level(level) if not consumable_types and not item_types: continue print("LEVEL " + str(level)) print("- - - - -") for c_type in consumable_types: print("{:<25}".format(c_type.name) + str(CONSUMABLES[c_type].description)) for i_type in item_types: data = get_item_data_by_type(i_type) description_lines = [line.text for line in create_item_description(randomized_item_id(i_type))] print("{:<25}".format(data.base_name) + ", ".join(description_lines)) print("")
def on_inventory_updated(self, item_slots: List[ItemInventorySlot]): for i in range(len(item_slots)): icon = self.inventory_icons[i] slot = item_slots[i] item_id = slot.get_item_id() if not slot.is_empty() else None slot_equipment_category = slot.enforced_equipment_category image = None tooltip = None if item_id: item_type = item_id.item_type data = get_item_data_by_type(item_type) image = self.images_by_ui_sprite[data.icon_sprite] category_name = None if data.item_equipment_category: category_name = ITEM_EQUIPMENT_CATEGORY_NAMES[ data.item_equipment_category] description_lines = create_item_description(item_id) item_name = item_id.name is_rare = bool(item_id.affix_stats) is_unique = data.is_unique tooltip = TooltipGraphics.create_for_item(self.ui_render, item_name, category_name, icon.rect.topleft, description_lines, is_rare=is_rare, is_unique=is_unique) elif slot_equipment_category: image = self.images_by_item_category[slot_equipment_category] category_name = ITEM_EQUIPMENT_CATEGORY_NAMES[ slot_equipment_category] tooltip_details = [ DetailLine("[" + category_name + "]"), DetailLine( "You have nothing equipped. Drag an item here to equip it!" ) ] tooltip = TooltipGraphics(self.ui_render, COLOR_WHITE, "...", tooltip_details, bottom_left=icon.rect.topleft) icon.image = image icon.tooltip = tooltip icon.slot_equipment_category = slot_equipment_category icon.item_id = item_id
def render(self): self.screen_render.rect( COLOR_BORDER, Rect(0, 0, self.camera_size[0], self.camera_size[1]), 1) self.screen_render.rect_filled( (20, 10, 0), Rect(0, self.camera_size[1], self.screen_size[0], self.screen_size[1] - self.camera_size[1])) # CONSUMABLES self.ui_render.rect_filled((60, 60, 80), self.consumable_icons_row) for icon in self.consumable_icons: # TODO treat this as state and update it elsewhere recently_clicked = icon.slot_number == self.highlighted_consumable_action icon.render(recently_clicked) # ABILITIES self.ui_render.rect_filled((60, 60, 80), self.ability_icons_row) for icon in self.ability_icons: ability_type = icon.ability_type # TODO treat this as state and update it elsewhere if ability_type: recently_clicked = ability_type == self.highlighted_ability_action icon.render(recently_clicked) # ITEMS self.ui_render.rect_filled((60, 60, 80), self.inventory_icons_rect) for icon in self.inventory_icons: # TODO treat this as state and update it elsewhere highlighted = False if self.item_slot_being_dragged and self.item_slot_being_dragged.item_id: item_type = self.item_slot_being_dragged.item_id.item_type item_data = get_item_data_by_type(item_type) highlighted = item_data.item_equipment_category \ and icon.slot_equipment_category == item_data.item_equipment_category if self.manually_highlighted_inventory_item and self.manually_highlighted_inventory_item == icon.item_id: highlighted = True icon.render(highlighted) # MINIMAP self.minimap.render() simple_components = [ self.exp_bar, self.portrait, self.healthbar, self.manabar, self.money_text, self.buffs, self.sound_checkbox, self.save_button, self.fullscreen_checkbox, self.stats_window, self.talents_window, self.quests_window, self.controls_window ] + self.toggle_buttons for component in simple_components: component.render() self.screen_render.rect(COLOR_BORDER, self.ui_screen_area, 1) self.screen_render.rect_transparent(Rect(1, 1, 70, 20), 100, COLOR_BLACK) self.screen_render.text(self.font_debug_info, "fps: " + self.fps_string, (6, 4)) if self.game_mode_string: self.screen_render.rect_transparent(Rect(1, 23, 70, 20), 100, COLOR_BLACK) self.screen_render.text(self.font_debug_info, self.game_mode_string, (6, 26)) self.message.render(self.info_message.message) # TODO Bring back relative render position for dragged entities if self.item_slot_being_dragged: self._render_item_being_dragged( self.item_slot_being_dragged.item_id, self.mouse_screen_position, (UI_ICON_SIZE[0] // 2, (UI_ICON_SIZE[1] // 2))) elif self.consumable_slot_being_dragged: self._render_consumable_being_dragged( self.consumable_slot_being_dragged.consumable_types[0], self.mouse_screen_position, (UI_ICON_SIZE[0] // 2, (UI_ICON_SIZE[1] // 2))) self.dialog.render() if self.hovered_component and self.hovered_component.tooltip and not self.item_slot_being_dragged \ and not self.consumable_slot_being_dragged: tooltip: TooltipGraphics = self.hovered_component.tooltip tooltip.render() self.paused_splash_screen.render()