From 0b38065123aeaa485a58f7fa6fa07ab32d7b7e35 Mon Sep 17 00:00:00 2001 From: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> Date: Sat, 18 Apr 2026 16:08:21 +0100 Subject: [PATCH] APQuest: Fix Easy Mode boss having too much health to beat (#6146) * Change the boss' health to 2 in easy mode, adjust boss graphics to reflect this behavior * graphics formatting --- worlds/apquest/client/ap_quest_client.py | 2 +- worlds/apquest/client/game_manager.py | 8 +++---- worlds/apquest/client/graphics.py | 27 ++++++++++++++--------- worlds/apquest/game/gameboard.py | 2 +- worlds/apquest/game/graphics/boss.png | Bin 580 -> 754 bytes 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/worlds/apquest/client/ap_quest_client.py b/worlds/apquest/client/ap_quest_client.py index bd67cc55ca..e875da7b68 100644 --- a/worlds/apquest/client/ap_quest_client.py +++ b/worlds/apquest/client/ap_quest_client.py @@ -198,7 +198,7 @@ class APQuestContext(CommonContext): if self.ap_quest_game is None: raise RuntimeError("Tried to render before self.ap_quest_game was initialized.") - self.ui.render(self.ap_quest_game, self.player_sprite) + self.ui.render(self.ap_quest_game, self.player_sprite, self.hard_mode) self.handle_game_events() def location_checked_side_effects(self, location: int) -> None: diff --git a/worlds/apquest/client/game_manager.py b/worlds/apquest/client/game_manager.py index ed2793da36..7d40a36ee3 100644 --- a/worlds/apquest/client/game_manager.py +++ b/worlds/apquest/client/game_manager.py @@ -88,23 +88,23 @@ class APQuestManager(GameManager): self.game_view.force_focus() self.sound_manager.game_started = True - def render(self, game: Game, player_sprite: PlayerSprite) -> None: + def render(self, game: Game, player_sprite: PlayerSprite, hard_mode: bool) -> None: self.setup_game_grid_if_not_setup(game) # This calls game.render(), which needs to happen to update the state of math traps - self.render_gameboard(game, player_sprite) + self.render_gameboard(game, player_sprite, hard_mode) # Only now can we check whether a math problem is active self.render_background_game_grid(game.gameboard.size, game.active_math_problem is None) self.sound_manager.math_trap_active = game.active_math_problem is not None self.render_item_column(game) - def render_gameboard(self, game: Game, player_sprite: PlayerSprite) -> None: + def render_gameboard(self, game: Game, player_sprite: PlayerSprite, hard_mode: bool) -> None: rendered_gameboard = game.render() for gameboard_row, image_row in zip(rendered_gameboard, self.top_image_grid, strict=False): for graphic, image in zip(gameboard_row, image_row[:11], strict=False): - texture = get_texture(graphic, player_sprite) + texture = get_texture(graphic, player_sprite, hard_mode) if texture is None: image.opacity = 0 diff --git a/worlds/apquest/client/graphics.py b/worlds/apquest/client/graphics.py index 0e31218c6f..9acf7c9987 100644 --- a/worlds/apquest/client/graphics.py +++ b/worlds/apquest/client/graphics.py @@ -29,6 +29,7 @@ class RelatedTexture(NamedTuple): IMAGE_GRAPHICS: dict[Graphic, str | RelatedTexture] = { + # Inanimates Graphic.WALL: RelatedTexture("inanimates.png", 16, 32, 16, 16), Graphic.BREAKABLE_BLOCK: RelatedTexture("inanimates.png", 32, 32, 16, 16), Graphic.CHEST: RelatedTexture("inanimates.png", 0, 16, 16, 16), @@ -37,29 +38,25 @@ IMAGE_GRAPHICS: dict[Graphic, str | RelatedTexture] = { Graphic.BUTTON_NOT_ACTIVATED: RelatedTexture("inanimates.png", 0, 0, 16, 16), Graphic.BUTTON_ACTIVATED: RelatedTexture("inanimates.png", 16, 0, 16, 16), Graphic.BUTTON_DOOR: RelatedTexture("inanimates.png", 32, 0, 16, 16), - + # Enemies Graphic.NORMAL_ENEMY_1_HEALTH: RelatedTexture("normal_enemy.png", 0, 0, 16, 16), Graphic.NORMAL_ENEMY_2_HEALTH: RelatedTexture("normal_enemy.png", 16, 0, 16, 16), - Graphic.BOSS_5_HEALTH: RelatedTexture("boss.png", 16, 16, 16, 16), Graphic.BOSS_4_HEALTH: RelatedTexture("boss.png", 0, 16, 16, 16), Graphic.BOSS_3_HEALTH: RelatedTexture("boss.png", 32, 32, 16, 16), Graphic.BOSS_2_HEALTH: RelatedTexture("boss.png", 16, 32, 16, 16), Graphic.BOSS_1_HEALTH: RelatedTexture("boss.png", 0, 32, 16, 16), - + # Items Graphic.EMPTY_HEART: RelatedTexture("hearts.png", 0, 0, 16, 16), Graphic.HEART: RelatedTexture("hearts.png", 16, 0, 16, 16), Graphic.HALF_HEART: RelatedTexture("hearts.png", 32, 0, 16, 16), - Graphic.REMOTE_ITEM: RelatedTexture("items.png", 0, 16, 16, 16), Graphic.CONFETTI_CANNON: RelatedTexture("items.png", 16, 16, 16, 16), Graphic.HAMMER: RelatedTexture("items.png", 32, 16, 16, 16), Graphic.KEY: RelatedTexture("items.png", 0, 0, 16, 16), Graphic.SHIELD: RelatedTexture("items.png", 16, 0, 16, 16), Graphic.SWORD: RelatedTexture("items.png", 32, 0, 16, 16), - - Graphic.ITEMS_TEXT: "items_text.png", - + # Numbers Graphic.ZERO: RelatedTexture("numbers.png", 0, 16, 16, 16), Graphic.ONE: RelatedTexture("numbers.png", 16, 16, 16, 16), Graphic.TWO: RelatedTexture("numbers.png", 32, 16, 16, 16), @@ -70,26 +67,29 @@ IMAGE_GRAPHICS: dict[Graphic, str | RelatedTexture] = { Graphic.SEVEN: RelatedTexture("numbers.png", 32, 0, 16, 16), Graphic.EIGHT: RelatedTexture("numbers.png", 48, 0, 16, 16), Graphic.NINE: RelatedTexture("numbers.png", 64, 0, 16, 16), - + # Letters Graphic.LETTER_A: RelatedTexture("letters.png", 0, 16, 16, 16), Graphic.LETTER_E: RelatedTexture("letters.png", 16, 16, 16, 16), Graphic.LETTER_H: RelatedTexture("letters.png", 32, 16, 16, 16), Graphic.LETTER_I: RelatedTexture("letters.png", 0, 0, 16, 16), Graphic.LETTER_M: RelatedTexture("letters.png", 16, 0, 16, 16), Graphic.LETTER_T: RelatedTexture("letters.png", 32, 0, 16, 16), - + # Mathematical symbols Graphic.DIVIDE: RelatedTexture("symbols.png", 0, 16, 16, 16), Graphic.EQUALS: RelatedTexture("symbols.png", 16, 16, 16, 16), Graphic.MINUS: RelatedTexture("symbols.png", 32, 16, 16, 16), Graphic.PLUS: RelatedTexture("symbols.png", 0, 0, 16, 16), Graphic.TIMES: RelatedTexture("symbols.png", 16, 0, 16, 16), + # Other visual-only elements + Graphic.ITEMS_TEXT: "items_text.png", Graphic.NO: RelatedTexture("symbols.png", 32, 0, 16, 16), - Graphic.UNKNOWN: RelatedTexture("symbols.png", 32, 0, 16, 16), # Same as "No" } BACKGROUND_TILE = RelatedTexture("inanimates.png", 0, 32, 16, 16) +EASY_MODE_BOSS_2_HEALTH = RelatedTexture("boss.png", 16, 0, 16, 16) + class PlayerSprite(Enum): HUMAN = 0 @@ -160,13 +160,18 @@ def get_texture_by_identifier(texture_identifier: str | RelatedTexture) -> Textu return sub_texture -def get_texture(graphic: Graphic | Literal["Grass"], player_sprite: PlayerSprite | None = None) -> Texture | None: +def get_texture( + graphic: Graphic | Literal["Grass"], player_sprite: PlayerSprite | None = None, hard_mode: bool = False +) -> Texture | None: if graphic == Graphic.EMPTY: return None if graphic == "Grass": return get_texture_by_identifier(BACKGROUND_TILE) + if graphic == Graphic.BOSS_2_HEALTH and not hard_mode: + return get_texture_by_identifier(EASY_MODE_BOSS_2_HEALTH) + if graphic in IMAGE_GRAPHICS: return get_texture_by_identifier(IMAGE_GRAPHICS[graphic]) diff --git a/worlds/apquest/game/gameboard.py b/worlds/apquest/game/gameboard.py index 77688c2929..e034b3f71c 100644 --- a/worlds/apquest/game/gameboard.py +++ b/worlds/apquest/game/gameboard.py @@ -246,7 +246,7 @@ def create_gameboard(hard_mode: bool, hammer_exists: bool, extra_chest: bool) -> breakable_block = BreakableBlock() if hammer_exists else Empty() normal_enemy = EnemyWithLoot(2 if hard_mode else 1, Location.ENEMY_DROP) - boss = FinalBoss(5 if hard_mode else 3) + boss = FinalBoss(5 if hard_mode else 2) gameboard = ( (Empty(), Empty(), Empty(), Wall(), Empty(), Empty(), Empty(), Wall(), Empty(), Empty(), Empty()), diff --git a/worlds/apquest/game/graphics/boss.png b/worlds/apquest/game/graphics/boss.png index dbcda31048e2b5a46c56d537e69258bbad77cf5c..07a9af35c0f1005e67c19aba06ac376874e54fdd 100644 GIT binary patch delta 731 zcmV<10wn#!1o8!tBYyw^b5ch_0olnce*gdg1ZP1_K>z@;j|==^1poj5AY({UO#lFT zCIA3{ga82g0001h=l}q9FaQARU;qF*m;eA5aGbhPJOBUy24YJ`L;(K){{a7>y{D4^ z000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2kHb83mq-OeSdTq0006uNkl1HT(GMGqKK$>E+>v+yfzNEWZvbKqIvmdn+F z0dFjqtMffWr+-i$zq&*k7U2Eda+H#I@sPdlj0Xoc3fc2N`}%#nXORV*fjd1~3Zhr3^Ptm9L0)Nf%s<0sAhIuspbEMLutq@yN zl_ir4$ncs7Un;c}Bm4}!RxR+Ad>}zaI^!$(z*djf@_}?c--!>J)Me{SWpgc4h;bYUZGW>Ar6t?wu_&y-v14mkVLJIZk z@3-3r!~6TvuEc0Q&~Oh(>-oa|zEm{Y`Q1E(dsK~Qgyj2x$N-BJUluLM_>t(;nR6t8 zpck)LMHsag8t(yxdV5A0QM3O3xqBcVfj`;YmDlsK?*n23zV&=hc>v@|sV)Nb46pzI N002ovPDHLkV1m4>JkqQwfW=x15x$g_iIAIa|Dgw_gMsu{ydvxCx4zzs=GhWBxv;K*`&Jr^NfNX{y4Xw u(Vu4*5G7aO(t^yPzLaDn|KpE~lk^97TAf@fD40M10000