def _entity_action_text(self, entity_action_text: EntityActionText): entity_center_pos = entity_action_text.entity.get_center_position() header_prefix = "[Space] " header_line = header_prefix + entity_action_text.text detail_lines = [] for detail_entry in entity_action_text.details: detail_lines += split_text_into_lines(detail_entry, 30) if detail_lines: line_length = max(max([len(line) for line in detail_lines]), len(header_line)) else: line_length = len(header_line) rect_width = line_length * 8 rect_height = 16 + len(detail_lines) * 16 rect_pos = (entity_center_pos[0] - rect_width // 2, entity_center_pos[1] - 60) self.world_render.rect_transparent(Rect(rect_pos[0], rect_pos[1], rect_width, rect_height), 150, (0, 0, 0)) if entity_action_text.style == EntityActionTextStyle.LOOT_RARE: color = (190, 150, 250) elif entity_action_text.style == EntityActionTextStyle.LOOT_UNIQUE: color = (250, 250, 150) else: color = (255, 255, 255) self.world_render.text(self.font_npc_action, header_prefix, (rect_pos[0] + 4, rect_pos[1])) prefix_w = self.font_npc_action.size(header_prefix)[0] self.world_render.text(self.font_npc_action, entity_action_text.text, (rect_pos[0] + 4 + prefix_w, rect_pos[1]), color) for i, detail_line in enumerate(detail_lines): self.world_render.text(self.font_npc_action, detail_line, (rect_pos[0] + 4, rect_pos[1] + (i + 1) * 16))
def __init__(self, ui_render: DrawableArea, title_color: Tuple[int, int, int], title: str, details: List[str], bottom_left: Optional[Tuple[int, int]] = None, bottom_right: Optional[Tuple[int, int]] = None, top_right: Optional[Tuple[int, int]] = None): self._ui_render = ui_render self._font_header = pygame.font.Font(DIR_FONTS + 'Herculanum.ttf', 16) self._font_details = pygame.font.Font(DIR_FONTS + 'Monaco.dfont', 12) self._title_color = title_color self._title = title self._detail_lines = [] for detail in details: self._detail_lines += split_text_into_lines(detail, 32) w = 260 h = 60 + 17 * len(self._detail_lines) if bottom_left: self._rect = Rect(bottom_left[0], bottom_left[1] - h - 3, w, h) elif bottom_right: self._rect = Rect(bottom_right[0] - w, bottom_right[1] - h - 3, w, h) elif top_right: self._rect = Rect(top_right[0] - w, top_right[1] - 3, w, h) else: raise Exception("No position given for tooltip!")
def render(self, heroes: List[HeroId], selected_index: int): self.screen_render.fill(COLOR_BLACK) self.screen_render.rect(COLOR_WHITE, Rect(0, 0, self.screen_size[0], self.screen_size[1]), 1) y_0 = 200 x_mid = self.screen_size[0] // 2 x_base = x_mid - 175 self.screen_render.text_centered(self.font_large, "SELECT HERO", (x_mid, y_0 - 100)) for i, hero in enumerate(heroes): hero_data = HEROES[hero] sprite = hero_data.portrait_icon_sprite image = self.images_by_portrait_sprite[sprite] x = x_base + i * (PORTRAIT_ICON_SIZE[0] + 20) self.screen_render.image(image, (x, y_0)) if i == selected_index: self.screen_render.rect(COLOR_HIGHLIGHTED_ICON, Rect(x, y_0, PORTRAIT_ICON_SIZE[0], PORTRAIT_ICON_SIZE[1]), 3) else: self.screen_render.rect(COLOR_WHITE, Rect(x, y_0, PORTRAIT_ICON_SIZE[0], PORTRAIT_ICON_SIZE[1]), 1) self.screen_render.text_centered( self.font, hero.name, (x + PORTRAIT_ICON_SIZE[0] // 2, y_0 + PORTRAIT_ICON_SIZE[1] + 10)) description = HEROES[heroes[selected_index]].description description_lines = split_text_into_lines(description, 40) y_1 = 350 for i, description_line in enumerate(description_lines): self.screen_render.text(self.font, description_line, (x_base - 8, y_1 + i * 20)) y_2 = 500 self.screen_render.text_centered(self.font, "Choose with arrow-keys", (x_mid, y_2)) y_3 = 530 self.screen_render.text_centered(self.font, "Press Space/Enter to confirm", (x_mid, y_3))
def _render(self): self._ui_render.rect_filled((50, 50, 50), self._rect) self._ui_render.rect((80, 50, 50), self._rect, 2) w = 135 h = 20 x = self._rect.left + self._rect.w // 2 - w // 2 y = self._rect.top + 15 rect = Rect(x, y - 3, w, h) self._ui_render.rect_filled((40, 40, 40), rect) self._ui_render.text(self._font_header, "HELP", (x + 50, y)) x = self._rect[0] + 15 y = self._rect[1] + 45 self._ui_render.text(self._font_header, "Basic controls", (x, y), (220, 220, 250)) y += 24 text_basic_controls = split_text_into_lines( "Move with the arrow-keys. Attack with 'Q'. Use potions with the number-keys ('1' through '5').", 47) for line in text_basic_controls: self._ui_render.text(self._font_details, line, (x, y)) y += 16 y += 10 self._ui_render.text(self._font_header, "Inventory", (x, y), (220, 220, 250)) y += 24 text_inventory = "Potions and items can be moved around in your inventory by dragging them with the mouse. " \ "Wearables must be put in the appropriate inventory slot to be effective!" for line in split_text_into_lines(text_inventory, 47): self._ui_render.text(self._font_details, line, (x, y)) y += 16 y += 10 self._ui_render.text(self._font_header, "Interactions", (x, y), (220, 220, 250)) y += 24 text_inventory = "Use the 'Space' key to interact with NPC's and objects in your surroundings. Be sure to " \ "talk to NPC's to fill up on potions, and complete quests. " for line in split_text_into_lines(text_inventory, 47): self._ui_render.text(self._font_details, line, (x, y)) y += 16
def _entity_action_text(self, entity_action_text: EntityActionText): entity_center_pos = entity_action_text.entity.get_center_position() text = entity_action_text.text detail_lines = [] for detail_entry in entity_action_text.details: detail_lines += split_text_into_lines(detail_entry, 30) if detail_lines: line_length = max(max([len(line) for line in detail_lines]), len(text)) else: line_length = len(text) rect_width = line_length * 8 rect_height = 16 + len(detail_lines) * 16 rect_pos = (entity_center_pos[0] - rect_width // 2, entity_center_pos[1] - 60) self.world_render.rect_transparent(Rect(rect_pos[0], rect_pos[1], rect_width, rect_height), 150, (0, 0, 0)) self.world_render.text(self.font_npc_action, text, (rect_pos[0] + 4, rect_pos[1])) for i, detail_line in enumerate(detail_lines): self.world_render.text(self.font_npc_action, detail_line, (rect_pos[0] + 4, rect_pos[1] + (i + 1) * 16))
def _render(self): self._ui_render.rect_filled((50, 50, 50), self._rect) self._ui_render.rect((80, 50, 50), self._rect, 2) x_header = self._rect[0] + 35 x_left = self._rect[0] + 15 y_0 = self._rect[1] + 15 self._render_header((x_header, y_0), "QUESTS") y = y_0 + 40 for quest in self.active_quests: self._ui_render.text(self._font_header, "\"%s\"" % quest.name, (x_left, y), (220, 220, 250)) lines = split_text_into_lines(quest.description, 30) for i, line in enumerate(lines): line_space = 15 self._ui_render.text(self._font_details, line, (x_left, y + 20 + i * line_space)) y += 70 for quest in self.completed_quests: self._ui_render.text(self._font_header, "\"%s\"" % quest.name, (x_left, y), (220, 220, 250)) self._ui_render.text(self._font_details, "[Completed]", (x_left, y + 20)) y += 70
def _render(self): x_left = self._rect[0] x_right = self._rect[0] + self._rect[2] self._screen_render.rect((210, 180, 60), self._rect, 5) self._screen_render.rect_transparent(self._rect, 220, COLOR_BLACK) color_separator = (170, 140, 20) dialog_container_portrait_padding = 10 rect_portrait_pos = (x_left + dialog_container_portrait_padding, self._rect[1] + dialog_container_portrait_padding) self._screen_render.image(self._portrait_image, rect_portrait_pos) rect_portrait = Rect(rect_portrait_pos[0], rect_portrait_pos[1], self._portrait_image_size[0], self._portrait_image_size[1]) self._screen_render.rect((160, 160, 180), rect_portrait, 2) dialog_pos = (x_left + 120, self._rect[1] + 15) dialog_lines = split_text_into_lines(self._text_body, 50) for i, dialog_text_line in enumerate(dialog_lines): if i == 6: print("WARN: too long dialog for NPC!") break line_space = 23 line_pos = (dialog_pos[0] + 5, dialog_pos[1] + line_space * i) self._screen_render.text(self._font_dialog, dialog_text_line, line_pos, COLOR_WHITE) self._screen_render.line(color_separator, (x_left, self._y_options), (x_right, self._y_options), 2) for i, (option, rect) in enumerate(zip(self._options, self._option_rects)): x_option_text = rect.x + Dialog.OPTION_PADDING + 5 y_option_text = rect.y + Dialog.OPTION_PADDING + 2 color_highlight = COLOR_WHITE is_option_active = self._active_option_index == i color_option_text = COLOR_WHITE if is_option_active else (160, 160, 160) is_option_hovered = self._hovered_option_index == i if is_option_active: self._screen_render.rect_transparent(rect, 120, COLOR_WHITE) self._screen_render.rect(color_highlight, rect, 1) elif is_option_hovered: self._screen_render.rect(COLOR_HOVERED, rect, 1) self._screen_render.text(self._font_dialog, option.summary, (x_option_text, y_option_text), color_option_text) active_option = self._options[self._active_option_index] y_under_options = self._y_options + 2 * Dialog.OPTIONS_MARGIN \ + len(self._options) * (Dialog.OPTION_LINE_HEIGHT + 2 * Dialog.OPTION_PADDING) self._screen_render.line(color_separator, (x_left, y_under_options), (x_right, y_under_options), 2) if self._tall_detail_section: y_action_text = y_under_options + 15 + Dialog.DETAIL_SECTION_INCREASED_HEIGHT else: y_action_text = y_under_options + 15 if self._tall_detail_section: if active_option.detail_image is not None: active_option_image = active_option.detail_image pos_option_image = x_left + 6, y_under_options + 7 self._screen_render.image(active_option_image, pos_option_image) rect_option_image = Rect(pos_option_image[0], pos_option_image[1], self._option_image_size[0], self._option_image_size[1]) self._screen_render.rect((150, 150, 150), rect_option_image, 1) if active_option.detail_header is not None: self._screen_render.text(self._font_dialog, active_option.detail_header, (x_left + 14 + self._option_image_size[0] + 4, y_action_text - Dialog.DETAIL_SECTION_INCREASED_HEIGHT)) if active_option.detail_body is not None: detail_body_lines = split_text_into_lines(active_option.detail_body, 80) for i, line in enumerate(detail_body_lines): line_pos = (x_left + 10, y_action_text - Dialog.DETAIL_SECTION_INCREASED_HEIGHT + 35 + 20 * i) self._screen_render.text(self._font_dialog_option_detail_body, line, line_pos) action_text = active_option.detail_action_text self._screen_render.text(self._font_dialog, "[Space] : " + action_text, (x_left + 10, y_action_text))
def _render(self): tall_detail_section = any([ o.detail_body is not None or o.detail_header is not None or o.detail_image is not None for o in self.options ]) h_detail_section_expansion = 82 options_margin = 10 option_padding = 4 h_option_line = 20 if tall_detail_section: h_dialog_container = 310 + len( self.options) * (h_option_line + 2 * option_padding) else: h_dialog_container = 310 + len(self.options) * (h_option_line + 2 * option_padding) \ - h_detail_section_expansion rect_dialog_container = Rect(100, 35, 500, h_dialog_container) x_left = rect_dialog_container[0] x_right = rect_dialog_container[0] + rect_dialog_container[2] self.screen_render.rect((210, 180, 60), rect_dialog_container, 5) self.screen_render.rect_transparent(rect_dialog_container, 200, COLOR_BLACK) color_separator = (170, 140, 20) dialog_container_portrait_padding = 10 rect_portrait_pos = (x_left + dialog_container_portrait_padding, rect_dialog_container[1] + dialog_container_portrait_padding) self.screen_render.image(self.portrait_image, rect_portrait_pos) rect_portrait = Rect(rect_portrait_pos[0], rect_portrait_pos[1], self.portrait_image_size[0], self.portrait_image_size[1]) self.screen_render.rect((160, 160, 180), rect_portrait, 2) dialog_pos = (x_left + 120, rect_dialog_container[1] + 15) dialog_lines = split_text_into_lines(self.text_body, 35) for i, dialog_text_line in enumerate(dialog_lines): if i == 6: print("WARN: too long dialog for NPC!") break self.screen_render.text( self.font_dialog, dialog_text_line, (dialog_pos[0] + 5, dialog_pos[1] + 32 * i), COLOR_WHITE) y_above_options = dialog_pos[1] + 150 self.screen_render.line(color_separator, (x_left, y_above_options), (x_right, y_above_options), 2) for i, option in enumerate(self.options): x_option = x_left + 8 y_option = y_above_options + options_margin + i * ( h_option_line + 2 * option_padding) x_option_text = x_option + option_padding + 5 y_option_text = y_option + option_padding + 2 color_highlight = COLOR_WHITE is_option_active = self.active_option_index == i color_option_text = COLOR_WHITE if is_option_active else (160, 160, 160) if is_option_active: rect_highlight_active_option = Rect( x_option, y_option, rect_dialog_container[2] - 16, h_option_line + 2 * option_padding) self.screen_render.rect_transparent( rect_highlight_active_option, 120, COLOR_WHITE) self.screen_render.rect(color_highlight, rect_highlight_active_option, 1) self.screen_render.text(self.font_dialog, option.summary, (x_option_text, y_option_text), color_option_text) active_option = self.options[self.active_option_index] y_under_options = y_above_options + 2 * options_margin \ + len(self.options) * (h_option_line + 2 * option_padding) self.screen_render.line(color_separator, (x_left, y_under_options), (x_right, y_under_options), 2) if tall_detail_section: y_action_text = y_under_options + 15 + h_detail_section_expansion else: y_action_text = y_under_options + 15 if tall_detail_section: if active_option.detail_image is not None: active_option_image = active_option.detail_image pos_option_image = x_left + 6, y_under_options + 7 self.screen_render.image(active_option_image, pos_option_image) rect_option_image = Rect(pos_option_image[0], pos_option_image[1], self.option_image_size[0], self.option_image_size[1]) self.screen_render.rect((150, 150, 150), rect_option_image, 1) if active_option.detail_header is not None: self.screen_render.text( self.font_dialog, active_option.detail_header, (x_left + 14 + self.option_image_size[0] + 4, y_action_text - h_detail_section_expansion)) if active_option.detail_body is not None: detail_body_lines = split_text_into_lines( active_option.detail_body, 70) for i, line in enumerate(detail_body_lines): line_pos = (x_left + 10, y_action_text - h_detail_section_expansion + 35 + 20 * i) self.screen_render.text( self.font_dialog_option_detail_body, line, line_pos) action_text = active_option.detail_action_text self.screen_render.text(self.font_dialog, "[Space] : " + action_text, (x_left + 10, y_action_text))