Source code for scripts.nqp.ui_elements.blessing_menu
from __future__ import annotations
import logging
import random
from typing import TYPE_CHECKING
import pygame
from pygame_gui.core import ObjectID
from pygame_gui.core import UIElement as PygameUiElement
from pygame_gui.elements import UIImage, UITextBox, UIVerticalScrollBar, UIButton
from scripts.engine.core import utility
import scripts.engine.core.matter
from scripts.engine.widgets.window import Window
from scripts.engine.internal.constant import ASSET_PATH, GAP_SIZE, ICON_SIZE, GameState
from scripts.engine.internal.action import Skill, SkillModifier
from scripts.engine.internal.data import store
from scripts.engine.core.component import Knowledge
from scripts.engine.core import state
from scripts.nqp.actions.blessing import MoveFast, NoMove, AttackMove, Aftershock, SaltTheWound, KeepAnEvenKeel
if TYPE_CHECKING:
from typing import List, Optional, Tuple, Union, Type
from pygame_gui import UIManager
[docs]class BlessingMenu(Window):
"""
A menu for adding blessings.
"""
[docs] def __init__(self, rect: pygame.Rect, manager: UIManager, blessings: List[SkillModifier]):
# assigned blessings
self.blessings = blessings
# sections
self.sections: List[PygameUiElement] = []
self.section_base_positions: List[int] = []
# button tracking
self.apply_buttons: List[Tuple[Type[Skill], SkillModifier, UIButton]] = []
# complete base class init
super().__init__(rect, manager, object_id=ObjectID("#blessing_menu", "@menu_window"))
#self.set_dimensions((rect.width, rect.height))
# setup scroll bar
self.scrollbar_width = 50
self.scrollbar_size = 0.3
self.scrollbar = UIVerticalScrollBar(
pygame.Rect((rect.width - self.scrollbar_width, 0), (self.scrollbar_width, rect.height)),
self.scrollbar_size,
manager,
self,
self,
"#scrollbar",
)
# block mouse clicks outside of menu
self.set_blocking(True)
# show self
self.show()
# confirm init complete
logging.debug(f"Blessing menu initialized.")
def _shift_children(self, target_y):
for i, child in enumerate(self.sections):
child.set_relative_position((child.relative_rect.x, self.section_base_positions[i] - target_y))
[docs] def update(self, time_delta: float):
super().update(time_delta)
new_y_portion = self.scrollbar.scroll_position / self.scrollbar.bottom_limit / (1 - self.scrollbar_size)
if self.sections != []:
if (
self.section_base_positions[-1] + self.sections[-1].relative_rect.height
> self.rect.height - self.section_base_positions[0]
):
new_y = new_y_portion * (
self.section_base_positions[-1]
+ self.sections[-1].relative_rect.height
- (self.rect.height - self.section_base_positions[0])
+ 30 # the +30 accounts for a bug in window sizes from pygame_gui
)
self._shift_children(new_y)
for button in self.apply_buttons:
if button[2].check_pressed():
player = scripts.engine.core.matter.get_player()
knowledge = scripts.engine.core.matter.get_entitys_component(player, Knowledge)
knowledge.add_blessing(button[0], button[1])
state.set_new(GameState.GAME_MAP)
self.kill()
[docs] def show(self):
"""
fill in later
"""
super().show()
self.visible = True
# clear to refresh first
self.cleanse()
if 1:
info: List[Tuple[str, Union[str, pygame.Surface]]] = []
current_y = 0
width = self.rect.width - self.scrollbar_width
for blessing in self.blessings:
current_y = self._create_blessing_section(current_y, blessing)
#info.append(("text", "Please select a blessing."))
#info.append(("image", section_break_image))
# create the box for the info
#self._create_sections(info)
# refresh scrollbar
self.scrollbar.redraw_scrollbar()
def _create_blessing_section(self, current_y, blessing):
# get the break image
section_break_image = utility.get_image(
ASSET_PATH / "ui/menu_window_n_repeat.png", (self.rect.width - self.scrollbar_width, 13)
)
width = self.rect.width - self.scrollbar_width
# blessing name
rect = pygame.Rect((0, current_y), (width, 0))
ui_text = UITextBox(
html_text=blessing.name,
relative_rect=rect,
manager=self.ui_manager,
wrap_to_height=True,
layer_starting_height=1,
container=self.get_container(),
)
self.sections.append(ui_text)
self.section_base_positions.append(ui_text.relative_rect.y)
current_y += ui_text.rect.height + GAP_SIZE
# blessing description
rect = pygame.Rect((0, current_y), (width, 0))
ui_text = UITextBox(
html_text=blessing.description,
relative_rect=rect,
manager=self.ui_manager,
wrap_to_height=True,
layer_starting_height=1,
container=self.get_container(),
)
self.sections.append(ui_text)
self.section_base_positions.append(ui_text.relative_rect.y)
current_y += ui_text.rect.height + GAP_SIZE
# button section
player = scripts.engine.core.matter.get_player()
knowledge = scripts.engine.core.matter.get_entitys_component(player, Knowledge)
for skill in knowledge.skills.values():
if knowledge.can_add_blessing(skill, blessing):
# blessing can be applied to this skill, so add a button for it
apply_button = UIButton(
relative_rect=pygame.Rect((5, current_y), (width - 10, 40)),
text=skill.__name__,
manager=self.ui_manager,
container=self.get_container(),
)
self.sections.append(apply_button)
self.section_base_positions.append(apply_button.relative_rect.y)
self.apply_buttons.append((skill, blessing, apply_button))
current_y += apply_button.rect.height + GAP_SIZE
# create rect and image element
image_rect = pygame.Rect((0, current_y), (section_break_image.get_width(), section_break_image.get_height()))
ui_image = UIImage(
relative_rect=image_rect,
image_surface=section_break_image,
manager=self.ui_manager,
container=self.get_container(),
)
self.sections.append(ui_image)
self.section_base_positions.append(ui_image.relative_rect.y)
# update position
current_y += section_break_image.get_height() + GAP_SIZE
return current_y
[docs] def cleanse(self):
"""
Cleanse existing section info.
"""
# kill the box and clear the reference
for element in self.sections:
element.kill()
self.sections = []
def _create_sections(self, info: List[Tuple[str, Union[str, pygame.Surface]]]):
"""
Create sections for the information about the tile
"""
sections = []
section_base_positions = []
current_y = 0
current_text_block = ""
# draw info
x = 0
width = self.rect.width - self.scrollbar_width
text_height = 0 # box will resize height anyway
# loop each image provided and use as header for each group of info
for type_str, text_or_image in info:
# build current text block
if type_str == "text":
assert isinstance(text_or_image, str) # handle mypy error
current_text_block += text_or_image + "<br>"
elif type_str == "image":
assert isinstance(text_or_image, pygame.Surface) # handle mypy error
# if we have text in the previous block, show it
if current_text_block:
## Display text
rect = pygame.Rect((x, current_y), (width, text_height))
ui_text = UITextBox(
html_text=current_text_block,
relative_rect=rect,
manager=self.ui_manager,
wrap_to_height=True,
layer_starting_height=1,
container=self.get_container(),
)
sections.append(ui_text)
section_base_positions.append(ui_text.relative_rect.y)
# update position
current_y += ui_text.rect.height + GAP_SIZE
# clear to prevent any carry over
ui_text = None
current_text_block = ""
## Display image
# draw info
image_width = text_or_image.get_width()
image_height = text_or_image.get_height()
# if image is the icon_path then draw centre, otherwise draw left
if image_width == ICON_SIZE:
draw_x = int((self.rect.width / 2) - (image_width / 2))
else:
draw_x = 0
# create rect and image element
image_rect = pygame.Rect((draw_x, current_y), (image_width, image_height))
ui_image = UIImage(
relative_rect=image_rect,
image_surface=text_or_image,
manager=self.ui_manager,
container=self.get_container(),
)
sections.append(ui_image)
section_base_positions.append(ui_image.relative_rect.y)
# update position
current_y += image_height + GAP_SIZE
# clear to prevent any carry over
ui_image = None
# we've left the loop, clean up left over text
if current_text_block:
## Display text
rect = pygame.Rect((x, current_y), (width, text_height))
ui_text = UITextBox(
html_text=current_text_block,
relative_rect=rect,
manager=self.ui_manager,
wrap_to_height=True,
layer_starting_height=1,
container=self.get_container(),
)
sections.append(ui_text)
section_base_positions.append(ui_text.relative_rect.y)
# update main sections list
self.sections = sections
self.section_base_positions = section_base_positions
# post game event
#event_hub.post(ExitMenuEvent(UIElement.ACTOR_INFO))