~12 On Screen Messages~
3/30/2026

In this section we will be looking at how we can display messages, that the user can read on the screen. So far, all that we have had is messages being brought back to us about the game through the output panel. But the player can not see this panel. Being able to speak with the player about certain aspects of the game will be imperative. So, here we will be learning how we can go about doing this.
In order to be able to create these messages we will be implementing a second controller, similar to that other controller which we had built earlier. And instead of just one controller, now we will need to have two that will be thrown into our room.
The Heads Up Display Object
Create an object and name it:
obj_hud
HUD is a shortcut, or Acronym for the words ‘Heads up display’. It is a video game term for providing on-screen messages to the user. We do not need to worry about creating a sprite for this object, as it will be invisible inside of the room.
We will be using two Events for this Heads Up Display object. The first is the create event. Inside of the create event we want to put the very first thing that the display needs to do, and in this case it is to make sure that it is on top of everything else, we do not want any other graphics to be covering this one important element up. The player must be able to see it.
The second event will be the Draw GUI event. This will be used to dynamically draw the number of elements that the player has onto a type of score board that can be seen and utilized by the player to strategically make their way through the game.
Now put this code into the object that you just created.
DO NOT FORGET TO SLIDE INTO ROOM ONCE YOU CREATE THIS OBJECT
// ~~~~~~~~~~~~~~~~~HUD OBJECT - Heads-Up Display ~~~~~~~~~~~~~~~~~~~
// Place it in your room alongside the controller
// This displays hearts, apples, bombs, and floor number on screen
// ~~~~~~~~~~~~~~~~~~~~~~~~~ CREATE EVENT ~~~~~~~~~~~~~~~~~~~~~~
depth = -1000; // Draw on top of everything
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DRAW GUI EVENT~~~~~~~~~~~~~~~~~~~
// Set up text appearance
draw_set_color(c_white);
draw_set_font(-1); // Default font (or set your own font)
draw_set_halign(fa_left);
draw_set_valign(fa_top);
// Draw stats in top-left corner
draw_text(20, 20, "Hearts: " + string(global.hearts) + "/" + string(global.max_hearts));
draw_text(20, 40, "Apples: " + string(global.apples));
draw_text(20, 60, "Bombs: " + string(global.bombs_held));
draw_text(20, 80, "Floor: " + string(global.current_floor));
// Optional: Draw heart icons instead of numbers
// Uncomment this section if you have a heart sprite (spr_heart_icon)
/*
for (var i = 0; i < global.hearts; i++) {
draw_sprite(spr_heart_icon, 0, 150 + (i * 40), 30);
}
*/
// Optional: Draw with background for better readability
/*
// Draw semi-transparent background
draw_set_alpha(0.5);
draw_set_color(c_black);
draw_rectangle(10, 10, 200, 100, false);
draw_set_alpha(1);
// Draw text on top
draw_set_color(c_white);
draw_text(20, 20, "Hearts: " + string(global.hearts) + "/" + string(global.max_hearts));
draw_text(20, 40, "Apples: " + string(global.apples));
draw_text(20, 60, "Bombs: " + string(global.bombs_held));
draw_text(20, 80, "Floor: " + string(global.current_floor));
*/
Do not forget to slide this controller into the room, once it has been created, prior to testing the game. Or you will see nothing.
Error Checking
Make sure names of objects are correct, and (as I have said many times) make sure your new controller object is actually inside of the room.
Getting the HUD to work correctly with Restarting the Room
So, far there was not an issue with having the hero reach the door, and what happens. It simply just restarted the floor and we had a new maze. However, you will see that this behavior with the heads up display isn’t quite working. This is because the room is always restarting. Restarting the room, when the hero reaches the door, would acutally be a punishment, they should be allowed to go to the next floor or even successfully leave the dungeon all together.
So, we will need to make a few changes to the code.
Implementation Steps:
STEP 1: Create a new Script in GameMaker
- In GameMaker, create a new Script asset
- Name it something like scr_regenerate_maze
- Copy the entire contents of Regenerate Maze Function.gml into it. (This script will be following the image below)
- Save the script
// ~~~~~~~~~~~~~~~~~~ REGENERATE MAZE FUNCTION ~~~~~~~~~~~~~~~~~~~~
// Call this function to regenerate the maze without restarting the room
// This preserves all global variables (treasures, floor number, etc.)
// Uses your existing maze generation system
function regenerate_maze() {
show_debug_message("=== REGENERATING MAZE ===");
show_debug_message("Floor: " + string(global.current_floor));
show_debug_message("Hearts: " + string(global.hearts) + ", Apples: " + string(global.apples) + ", Bombs: " + string(global.bombs_held));
// STEP 1: Clean up existing maze objects
show_debug_message("Destroying old maze objects...");
// Destroy walls
with (obj_wall_plain) { instance_destroy(); }
with (obj_wall_crackedA) { instance_destroy(); }
with (obj_wall_crackedB) { instance_destroy(); }
// Destroy items
with (obj_heart) { instance_destroy(); }
with (obj_apple) { instance_destroy(); }
with (obj_bomb) { instance_destroy(); }
with (obj_hazard_bomb) { instance_destroy(); } // Fixed name!
// Destroy door and thrown bombs
with (obj_door) { instance_destroy(); }
with (obj_bomb_thrown) { instance_destroy(); }
show_debug_message("Old objects destroyed.");
// STEP 2: Generate new maze using existing system
show_debug_message("Generating new maze...");
var target_width = 1280;
var target_height = 704;
var cell_size = 128;
var maze_width = floor(target_width / cell_size);
var maze_height = floor(target_height / cell_size);
// New random seed
var time_seed = get_timer();
random_set_seed(time_seed);
// Use your existing maze generation system
global.myMaze = new maze("recursive_backtrack", maze_width, maze_height);
maze_generate(global.myMaze);
spawn_maze_walls(global.myMaze, cell_size, 0, 0);
// STEP 3: Reposition hero and spawn door
spawn_object_in_opening(global.myMaze.heroWallSide, global.myMaze.heroPosition, cell_size, global.myMaze.w, global.myMaze.h, object_hero, "Hero");
spawn_object_in_opening(global.myMaze.doorWallSide, global.myMaze.doorPosition, cell_size, global.myMaze.w, global.myMaze.h, obj_door, "Door");
// Update hero start position
var hero = instance_find(object_hero, 0);
if (hero != noone) {
global.hero_start_x = hero.x;
global.hero_start_y = hero.y;
}
// STEP 4: Spawn items using existing system
var hearts_to_spawn = irandom_range(1, 2);
var apples_to_spawn = irandom_range(1, 2);
var bombs_to_spawn = irandom_range(1, 2);
var hazards_to_spawn = irandom_range(0, 2);
spawn_guaranteed_items(global.myMaze, cell_size, hearts_to_spawn, apples_to_spawn, bombs_to_spawn, hazards_to_spawn);
show_debug_message("=== MAZE REGENERATION COMPLETE ===");
show_debug_message("Now on Floor " + string(global.current_floor));
}
STEP 2: Rewrite the Hero’s step event
- Open your Hero object's Step Event
// Includes item collection, damage handling, and bomb throwing
// MOVEMENT INPUT (Your existing code)
var move_x = keyboard_check(vk_right) - keyboard_check(vk_left);
var move_y = keyboard_check(vk_down) - keyboard_check(vk_up);
var spd = 4;
var dx = move_x * spd;
var dy = move_y * spd;
// COLLISION CHECK & MOVEMENT with WALL GLIDING
if (dx != 0 || dy != 0) {
// Check full diagonal move
if (!place_meeting(x + dx, y + dy, obj_wall_plain) &&
!place_meeting(x + dx, y + dy, obj_wall_crackedA) &&
!place_meeting(x + dx, y + dy, obj_wall_crackedB)) {
x += dx;
y += dy;
} else {
// Wall gliding: Try to slide along walls smoothly
var moved = false;
// Try horizontal only
if (dx != 0 && !place_meeting(x + dx, y, obj_wall_plain) &&
!place_meeting(x + dx, y, obj_wall_crackedA) &&
!place_meeting(x + dx, y, obj_wall_crackedB)) {
x += dx;
moved = true;
}
// Try vertical only
if (dy != 0 && !place_meeting(x, y + dy, obj_wall_plain) &&
!place_meeting(x, y + dy, obj_wall_crackedA) &&
!place_meeting(x, y + dy, obj_wall_crackedB)) {
y += dy;
moved = true;
}
// If still stuck in wall - AGGRESSIVE AUTO-ESCAPE
if (place_meeting(x, y, obj_wall_plain) ||
place_meeting(x, y, obj_wall_crackedA) ||
place_meeting(x, y, obj_wall_crackedB)) {
show_debug_message("HERO STUCK IN WALL - AUTO ESCAPING!");
// Try to nudge out in 8 directions with larger distance
var nudge_distance = 16;
var escaped = false;
for (var angle = 0; angle < 360; angle += 45) {
var nudge_x = lengthdir_x(nudge_distance, angle);
var nudge_y = lengthdir_y(nudge_distance, angle);
if (!place_meeting(x + nudge_x, y + nudge_y, obj_wall_plain) &&
!place_meeting(x + nudge_x, y + nudge_y, obj_wall_crackedA) &&
!place_meeting(x + nudge_x, y + nudge_y, obj_wall_crackedB)) {
x += nudge_x;
y += nudge_y;
escaped = true;
show_debug_message("Hero auto-escaped from wall at angle " + string(angle) + "!");
break;
}
}
// If 16px didn't work, try 32px
if (!escaped) {
show_debug_message("Trying larger escape distance...");
nudge_distance = 32;
for (var angle = 0; angle < 360; angle += 45) {
var nudge_x = lengthdir_x(nudge_distance, angle);
var nudge_y = lengthdir_y(nudge_distance, angle);
if (!place_meeting(x + nudge_x, y + nudge_y, obj_wall_plain) &&
!place_meeting(x + nudge_x, y + nudge_y, obj_wall_crackedA) &&
!place_meeting(x + nudge_x, y + nudge_y, obj_wall_crackedB)) {
x += nudge_x;
y += nudge_y;
escaped = true;
show_debug_message("Hero escaped at 32px distance!");
break;
}
}
}
// Last resort - teleport to calculated safe position
if (!escaped) {
show_debug_message("Could not auto-escape - finding safe location!");
// Calculate center of room as fallback
var safe_x = room_width / 2;
var safe_y = room_height / 2;
// If center is also in wall, try a grid search for ANY safe spot
if (place_meeting(safe_x, safe_y, obj_wall_plain) ||
place_meeting(safe_x, safe_y, obj_wall_crackedA) ||
place_meeting(safe_x, safe_y, obj_wall_crackedB)) {
show_debug_message("Center blocked - searching for safe spot...");
var found_safe = false;
// Search in a grid pattern for a safe spot
for (var check_x = 128; check_x < room_width - 128; check_x += 64) {
for (var check_y = 128; check_y < room_height - 128; check_y += 64) {
if (!place_meeting(check_x, check_y, obj_wall_plain) &&
!place_meeting(check_x, check_y, obj_wall_crackedA) &&
!place_meeting(check_x, check_y, obj_wall_crackedB)) {
safe_x = check_x;
safe_y = check_y;
found_safe = true;
break;
}
}
if (found_safe) break;
}
}
x = safe_x;
y = safe_y;
show_debug_message("Teleported to safe location: (" + string(safe_x) + ", " + string(safe_y) + ")");
}
}
}
}
// EMERGENCY ESCAPE SYSTEM
// Press R to find a safe position (doesn't rely on spawn being safe)
if (keyboard_check_pressed(ord("R"))) {
show_debug_message("=== EMERGENCY ESCAPE ACTIVATED ===");
// First try the original spawn position
if (!place_meeting(global.hero_start_x, global.hero_start_y, obj_wall_plain) &&
!place_meeting(global.hero_start_x, global.hero_start_y, obj_wall_crackedA) &&
!place_meeting(global.hero_start_x, global.hero_start_y, obj_wall_crackedB)) {
x = global.hero_start_x;
y = global.hero_start_y;
show_debug_message("Returned to spawn: (" + string(x) + ", " + string(y) + ")");
} else {
// Spawn is blocked, find a safe spot
show_debug_message("Spawn blocked - searching for safe location...");
var safe_x = room_width / 2;
var safe_y = room_height / 2;
// If center is also in wall, do a grid search
if (place_meeting(safe_x, safe_y, obj_wall_plain) ||
place_meeting(safe_x, safe_y, obj_wall_crackedA) ||
place_meeting(safe_x, safe_y, obj_wall_crackedB)) {
var found_safe = false;
// Search in a grid pattern for ANY safe spot
for (var check_x = 128; check_x < room_width - 128; check_x += 64) {
for (var check_y = 128; check_y < room_height - 128; check_y += 64) {
if (!place_meeting(check_x, check_y, obj_wall_plain) &&
!place_meeting(check_x, check_y, obj_wall_crackedA) &&
!place_meeting(check_x, check_y, obj_wall_crackedB)) {
safe_x = check_x;
safe_y = check_y;
found_safe = true;
break;
}
}
if (found_safe) break;
}
}
x = safe_x;
y = safe_y;
show_debug_message("Escaped to safe location: (" + string(safe_x) + ", " + string(safe_y) + ")");
}
// Optional: Play a sound effect
// audio_play_sound(snd_teleport, 1, false);
}
// DEBUG: FORCE HERO INTO WALL (TEMPORARY - REMOVE AFTER TESTING)
// Press T to teleport hero into a wall for testing the escape system
if (keyboard_check_pressed(ord("T"))) {
// Find a wall and teleport hero into it
var test_wall = instance_find(obj_wall_plain, 0);
if (test_wall != noone) {
x = test_wall.x;
y = test_wall.y;
show_debug_message("=== DEBUG: TELEPORTED INTO WALL FOR TESTING ===");
show_debug_message("Position: (" + string(x) + ", " + string(y) + ")");
show_debug_message("Press R to test emergency escape!");
} else {
show_debug_message("No walls found to teleport into.");
}
}
// SPRITE SWITCHING (Your existing code)
if (move_y < 0) {
sprite_index = sprite_hero_back;
} else if (move_x > 0) {
sprite_index = sprite_hero_right;
} else if (move_x < 0) {
sprite_index = sprite_hero_left;
} else {
sprite_index = sprite_hero;
}
// NEW: ITEM COLLECTION
// --- Collect Heart ---
var item_heart = instance_place(x, y, obj_heart);
if (item_heart != noone) {
// Heal 1 heart
global.hearts += 1;
if (global.hearts > global.max_hearts) {
global.hearts = global.max_hearts;
}
show_debug_message("Collected heart! Hearts: " + string(global.hearts) + "/" + string(global.max_hearts));
instance_destroy(item_heart);
// Optional: Play sound effect
// audio_play_sound(snd_collect_heart, 1, false);
}
// --- Collect Apple (Gysahi Greens style) ---
var item_apple = instance_place(x, y, obj_apple);
if (item_apple != noone) {
global.apples += 1;
show_debug_message("Collected apple! Total: " + string(global.apples));
instance_destroy(item_apple);
// Optional: Add special effect (like in Chocobo's Dungeon)
// Could heal 1 heart or give temporary speed boost
// audio_play_sound(snd_collect_apple, 1, false);
}
// --- Collect Bomb (Gold pickup) ---
var item_bomb = instance_place(x, y, obj_bomb);
if (item_bomb != noone) {
global.bombs_held += 1;
show_debug_message("Picked up bomb! Total bombs: " + string(global.bombs_held));
instance_destroy(item_bomb);
// Optional: Play sound effect
// audio_play_sound(snd_collect_bomb, 1, false);
}
// NEW: BOMB THROWING
// Press SPACE to throw a bomb
if (keyboard_check_pressed(vk_space)) {
if (global.bombs_held > 0) {
global.bombs_held -= 1;
// Determine throw direction based on sprite
var throw_direction = 270; // Default: down
if (sprite_index == sprite_hero_back) {
throw_direction = 90; // Throw up
} else if (sprite_index == sprite_hero_right) {
throw_direction = 0; // Throw right
} else if (sprite_index == sprite_hero_left) {
throw_direction = 180; // Throw left
} else {
throw_direction = 270; // Throw down
}
// Create the bomb projectile slightly ahead of hero
var offset_distance = 32; // Spawn bomb 32 pixels ahead
var bomb_x = x + lengthdir_x(offset_distance, throw_direction);
var bomb_y = y + lengthdir_y(offset_distance, throw_direction);
var bomb = instance_create_layer(bomb_x, bomb_y, "Instances", obj_bomb_thrown);
bomb.direction = throw_direction;
bomb.image_angle = throw_direction;
show_debug_message("Threw bomb! Bombs remaining: " + string(global.bombs_held));
// Optional: Play throw sound
// audio_play_sound(snd_throw_bomb, 1, false);
} else {
show_debug_message("No bombs to throw!");
}
}
// NEW: CHECK FOR HAZARDS (Black hazard bomb damages you)
// obj_hazard_bomb is the BLACK hazard bomb that damages the hero
var hazard_bomb = instance_place(x, y, obj_hazard_bomb);
if (hazard_bomb != noone) {
// Take damage
global.hearts -= 1;
show_debug_message("Hit a black bomb! Lost 1 heart. Hearts remaining: " + string(global.hearts));
// Destroy the hazard
instance_destroy(hazard_bomb);
// Check if hero died
if (global.hearts <= 0) {
show_debug_message("Hero died! Resetting to floor start...");
// Teleport back to start
x = global.hero_start_x;
y = global.hero_start_y;
// Reset hearts
global.hearts = 3;
show_debug_message("Respawned at: (" + string(x) + ", " + string(y) + ")");
show_debug_message("Hearts restored to: " + string(global.hearts));
}
// Optional: Play damage sound and show damage animation
// audio_play_sound(snd_take_damage, 1, false);
}
// CHECK FOR EXIT (Your existing code)
if (place_meeting(x, y, obj_door)) {
show_debug_message("Hero reached the dungeon exit!");
global.current_floor += 1;
show_debug_message("Advancing to floor " + string(global.current_floor));
regenerate_maze(); // NEW - keeps treasures and floor number
}
Seeing the Heads Up Display Better
Right now,(if you were to run the game) you will see that the Heads up Display, is done in white text, and it is also off to the left side of the dungeon, just a bit. We might want to change this positioning and give the text a background and maybe even a border. This way we can see it better inside of any dungeon with any color background.
Above, you can see what the code is giving us so far. With just a few more changes to our code, we can change it to look like a scoreboard type of heads-up-display that we have in the image below.
// ~~~~~~~~~~~~~~~~~ HUD OBJECT - Heads-Up Display ~~~~~~~~~~~~~~~~~~~
// DRAW GUI EVENT
// Set up HUD panel dimensions
var hud_width = 200;
var hud_height = 110;
var padding = 10;
// Center the HUD at the top of the screen
var gui_width = display_get_gui_width();
var hud_x = (gui_width / 2) - (hud_width / 2);
var hud_y = 10;
// Draw background panel (semi-transparent black)
draw_set_alpha(0.7);
draw_set_color(c_black);
draw_rectangle(hud_x, hud_y, hud_x + hud_width, hud_y + hud_height, false);
// Draw border (white outline)
draw_set_alpha(1);
draw_set_color(c_white);
draw_rectangle(hud_x, hud_y, hud_x + hud_width, hud_y + hud_height, true);
// Draw inner border for extra visibility
draw_set_color(c_dkgray);
draw_rectangle(hud_x + 1, hud_y + 1, hud_x + hud_width - 1, hud_y + hud_height - 1, true);
// Set up text appearance
draw_set_color(c_white);
draw_set_font(-1); // Default font (or set your own font)
draw_set_halign(fa_left);
draw_set_valign(fa_top);
draw_set_alpha(1);
// Draw stats inside the panel
var text_x = hud_x + padding;
var text_y = hud_y + padding;
var line_height = 20;
draw_text(text_x, text_y, "Hearts: " + string(global.hearts) + "/" + string(global.max_hearts));
draw_text(text_x, text_y + line_height, "Apples: " + string(global.apples));
draw_text(text_x, text_y + line_height * 2, "Bombs: " + string(global.bombs_held));
draw_text(text_x, text_y + line_height * 3, "Floor: " + string(global.current_floor));
// Optional: Draw heart icons instead of numbers
// Uncomment this section if you have a heart sprite (spr_heart_icon)
/*
for (var i = 0; i < global.hearts; i++) {
draw_sprite(spr_heart_icon, 0, text_x + 80 + (i * 20), text_y + 5);
}
*/
Drawing a Heart instead of using Numbers
When we finish with this next section, this is what your scoreboard should be looking like. Sporting some cute little hearts in place of using a count displayed in numbers. This will certainly give this little section of your game board a bit more pizasz.
In order to accomplish this, first we will need to make another sprite. We can use the heart sprite that we already have for a pickup, but save in in a 16 x16 size, inside of Photoshop and throw it back into the Game Maker Game folder, so we can make a sprite out of it.
C:\Users\YOUR_USER_NAME\GameMakerProjects
Since this sprite will be used in code, you will need to name it exactly like this:
spr_heart_icon
Notice that the code will call directly to the sprite, there is no need to use an object. The Draw code can draw the sprite, just as a sprite.
Remember, though to import the little sprite image for your new icon.
Now, if you do want to go this route, and make little hearts as opposed to using a count, we will need to replace the code in both the HUD Object, and the Object Controllers, Create Event.
Rewrite the Draw GUI Event for the HUD Object
// ~~~~~~~~~~~~~~~ HUD Object -DRAW GUI EVENT ~~~~~~~~~~~~~~~~~~~~~~
// Set up HUD panel dimensions
var hud_width = 200;
var hud_height = 110;
var padding = 10;
// Center the HUD at the top of the screen
var gui_width = display_get_gui_width();
var hud_x = (gui_width / 2) - (hud_width / 2);
var hud_y = 10;
// Draw background panel (semi-transparent black)
draw_set_alpha(0.7);
draw_set_color(c_black);
draw_rectangle(hud_x, hud_y, hud_x + hud_width, hud_y + hud_height, false);
// Draw border (white outline)
draw_set_alpha(1);
draw_set_color(c_white);
draw_rectangle(hud_x, hud_y, hud_x + hud_width, hud_y + hud_height, true);
// Draw inner border for extra visibility
draw_set_color(c_dkgray);
draw_rectangle(hud_x + 1, hud_y + 1, hud_x + hud_width - 1, hud_y + hud_height - 1, true);
// Set up text appearance
draw_set_color(c_white);
draw_set_font(-1); // Default font (or set your own font)
draw_set_halign(fa_left);
draw_set_valign(fa_top);
draw_set_alpha(1);
// Draw stats inside the panel
var text_x = hud_x + padding;
var text_y = hud_y + padding;
var line_height = 20;
// Draw "Hearts:" label
draw_text(text_x, text_y, "Hearts:");
// Draw heart icons - filled hearts for current health, empty for lost health
var heart_start_x = text_x + 70; // Position after "Hearts:" text with padding
var heart_spacing = 18; // Space between each heart icon
// Draw filled hearts for current health
for (var i = 0; i < global.hearts; i++) {
draw_sprite(spr_heart_icon, 0, heart_start_x + (i * heart_spacing), text_y + 2);
}
// Draw empty/grayed hearts for lost health
for (var i = global.hearts; i < global.max_hearts; i++) {
draw_sprite_ext(spr_heart_icon, 0, heart_start_x + (i * heart_spacing), text_y + 2,
1, 1, 0, c_gray, 0.4); // Gray and semi-transparent for lost hearts
}
// Draw other stats
draw_text(text_x, text_y + line_height, "Apples: " + string(global.apples));
draw_text(text_x, text_y + line_height * 2, "Bombs: " + string(global.bombs_held));
draw_text(text_x, text_y + line_height * 3, "Floor: " + string(global.current_floor));
In the obj_controller – Create Event
//~~~~~~~~~~ CONTROLLER OBJECT CREATE EVENT ~~~~~~~~~~~~~~~~~~~~~~
// Integrates item system with maze generation
// for 1280x704 room size
// STEP 1: INITIALIZE ITEM SYSTEM
show_debug_message("=== INITIALIZING ITEM SYSTEM ===");
global.hearts = 3; // Starting lives
global.max_hearts = 5; // Maximum hearts
global.apples = 0; // Gysahi Greens counter
global.bombs_held = 0; // Bombs in inventory
global.current_floor = 1; // Current dungeon floor
global.hero_start_x = 0; // Will be saved after spawn
global.hero_start_y = 0; // Will be saved after spawn
show_debug_message("Hearts: " + string(global.hearts) + "/" + string(global.max_hearts));
show_debug_message("Floor: " + string(global.current_floor));
show_debug_message("=== ITEM SYSTEM READY ===");
// STEP 2: GENERATE MAZE (Your existing code)
var target_width = 1280;
var target_height = 704;
var cell_size = 128;
var maze_width = floor(target_width / cell_size);
var maze_height = floor(target_height / cell_size);
show_debug_message("=== CREATING MAZE FOR NEW ROOM SIZE ===");
show_debug_message("Room dimensions: " + string(target_width) + " x " + string(target_height));
show_debug_message("Creating maze: " + string(maze_width) + " x " + string(maze_height) + " cells");
show_debug_message("Cell size: " + string(cell_size) + "px");
show_debug_message("Wall size: 32px");
var time_seed = get_timer();
random_set_seed(time_seed);
show_debug_message("Random seed set to: " + string(time_seed));
show_debug_message("Testing random values: " + string(irandom(100)) + ", " + string(irandom(100)) + ", " + string(irandom(100)));
// Create and generate the maze
global.myMaze = new maze("recursive_backtrack", maze_width, maze_height);
maze_generate(global.myMaze);
// Spawn the maze walls
spawn_maze_walls(global.myMaze, cell_size, 0, 0);
// Spawn hero and door
spawn_object_in_opening(global.myMaze.heroWallSide, global.myMaze.heroPosition, cell_size, global.myMaze.w, global.myMaze.h, object_hero, "Hero");
spawn_object_in_opening(global.myMaze.doorWallSide, global.myMaze.doorPosition, cell_size, global.myMaze.w, global.myMaze.h, obj_door, "Door");
show_debug_message("=== MAZE SETUP COMPLETE ===");
// STEP 3: SAVE HERO STARTING POSITION
show_debug_message("=== SAVING HERO START POSITION ===");
var hero = instance_find(object_hero, 0);
if (hero != noone) {
global.hero_start_x = hero.x;
global.hero_start_y = hero.y;
show_debug_message("Hero start position saved: (" + string(global.hero_start_x) + ", " + string(global.hero_start_y) + ")");
} else {
show_debug_message("WARNING: Could not find hero to save position!");
}
// STEP 4: SPAWN ITEMS IN MAZE
// Balanced spawning: 1-2 of each item type
// Random amount between 1-2 for each item
var hearts_to_spawn = irandom_range(1, 2);
var apples_to_spawn = irandom_range(1, 2);
var bombs_to_spawn = irandom_range(1, 2);
var hazards_to_spawn = irandom_range(1, 2); // 1-2 hazard bombs (guaranteed spawn)
spawn_guaranteed_items(global.myMaze, cell_size, hearts_to_spawn, apples_to_spawn, bombs_to_spawn, hazards_to_spawn);
// Alternative methods (comment out the above and uncomment one of these):
// OPTION 1: Pure random spawning (adjust spawn_chance in function)
// spawn_items_in_maze(global.myMaze, cell_size);
// OPTION 2: Fixed exact counts (hearts, apples, good bombs, hazard bombs)
// spawn_guaranteed_items(global.myMaze, cell_size, 2, 2, 2, 1);
show_debug_message("=== DUNGEON FLOOR " + string(global.current_floor) + " READY ===");