From a4de0d7a0462ab86f14ed2753ac945498ec69f30 Mon Sep 17 00:00:00 2001 From: EttyKitty <20323032+EttyKitty@users.noreply.github.com> Date: Fri, 10 Jul 2026 02:42:58 +0300 Subject: [PATCH 01/14] refactor: New planet methods for forces checking --- scripts/scr_PlanetData/scr_PlanetData.gml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/scripts/scr_PlanetData/scr_PlanetData.gml b/scripts/scr_PlanetData/scr_PlanetData.gml index d711546c6..6cabe180c 100644 --- a/scripts/scr_PlanetData/scr_PlanetData.gml +++ b/scripts/scr_PlanetData/scr_PlanetData.gml @@ -804,6 +804,24 @@ function PlanetData(_planet, _system) constructor { return xh_force; }; + static has_enemy_force = function() { + for (var i = 1; i < array_length(planet_forces); i++) { + if (planet_forces[i] > 0 && obj_controller.faction_status[i] == "War") { + return true; + } + } + return false; + }; + + static has_any_force = function() { + for (var i = 1; i < array_length(planet_forces); i++) { + if (planet_forces[i] > 0) { + return true; + } + } + return false; + }; + static has_feature = function(feature) { return planet_feature_bool(features, feature); }; From 0e21af142e41d8e8cb45bf748a8b1ec2654c87d1 Mon Sep 17 00:00:00 2001 From: EttyKitty <20323032+EttyKitty@users.noreply.github.com> Date: Fri, 10 Jul 2026 02:48:13 +0300 Subject: [PATCH 02/14] feat: Refine planet button logic and code --- objects/obj_en_fleet/Draw_0.gml | 32 +++--- objects/obj_p_fleet/Draw_0.gml | 23 +---- objects/obj_star_select/Create_0.gml | 12 +-- objects/obj_star_select/Draw_64.gml | 120 +++++++++------------- scripts/scr_PlanetData/scr_PlanetData.gml | 4 +- scripts/scr_void_click/scr_void_click.gml | 27 +---- 6 files changed, 74 insertions(+), 144 deletions(-) diff --git a/objects/obj_en_fleet/Draw_0.gml b/objects/obj_en_fleet/Draw_0.gml index 0a1d187be..e1e8fe7e2 100644 --- a/objects/obj_en_fleet/Draw_0.gml +++ b/objects/obj_en_fleet/Draw_0.gml @@ -48,29 +48,29 @@ if (obj_controller.zoomed == 1) { } } -if (obj_controller.selecting_planet > 0) { - if ((mouse_x >= camera_get_view_x(view_camera[0]) + 529) && (mouse_y >= camera_get_view_y(view_camera[0]) + 234) && (mouse_x < camera_get_view_x(view_camera[0]) + 611) && (mouse_y < camera_get_view_y(view_camera[0]) + 249)) { - if (instance_exists(obj_star_select)) { - if (obj_star_select.button1 != "") { - within = 0; + if (obj_controller.selecting_planet > 0) { + if ((mouse_x >= camera_get_view_x(view_camera[0]) + 529) && (mouse_y >= camera_get_view_y(view_camera[0]) + 234) && (mouse_x < camera_get_view_x(view_camera[0]) + 611) && (mouse_y < camera_get_view_y(view_camera[0]) + 249)) { + if (instance_exists(obj_star_select)) { + if (array_length(obj_star_select.buttons) > 0) { + within = 0; + } } } - } - if ((mouse_x >= camera_get_view_x(view_camera[0]) + 529) && (mouse_y >= camera_get_view_y(view_camera[0]) + 250) && (mouse_x < camera_get_view_x(view_camera[0]) + 611) && (mouse_y < camera_get_view_y(view_camera[0]) + 265)) { - if (instance_exists(obj_star_select)) { - if (obj_star_select.button2 != "") { - within = 0; + if ((mouse_x >= camera_get_view_x(view_camera[0]) + 529) && (mouse_y >= camera_get_view_y(view_camera[0]) + 250) && (mouse_x < camera_get_view_x(view_camera[0]) + 611) && (mouse_y < camera_get_view_y(view_camera[0]) + 265)) { + if (instance_exists(obj_star_select)) { + if (array_length(obj_star_select.buttons) > 1) { + within = 0; + } } } - } - if ((mouse_x >= camera_get_view_x(view_camera[0]) + 529) && (mouse_y >= camera_get_view_y(view_camera[0]) + 266) && (mouse_x < camera_get_view_x(view_camera[0]) + 611) && (mouse_y < camera_get_view_y(view_camera[0]) + 281)) { - if (instance_exists(obj_star_select)) { - if (obj_star_select.button3 != "") { - within = 0; + if ((mouse_x >= camera_get_view_x(view_camera[0]) + 529) && (mouse_y >= camera_get_view_y(view_camera[0]) + 266) && (mouse_x < camera_get_view_x(view_camera[0]) + 611) && (mouse_y < camera_get_view_y(view_camera[0]) + 281)) { + if (instance_exists(obj_star_select)) { + if (array_length(obj_star_select.buttons) > 2) { + within = 0; + } } } } -} if (action != "") { draw_set_halign(fa_left); diff --git a/objects/obj_p_fleet/Draw_0.gml b/objects/obj_p_fleet/Draw_0.gml index 9b352f166..6335f8e3e 100644 --- a/objects/obj_p_fleet/Draw_0.gml +++ b/objects/obj_p_fleet/Draw_0.gml @@ -66,29 +66,14 @@ if (!keyboard_check(vk_shift)) { } } -if (obj_controller.selecting_planet > 0) { - if ((mouse_x >= camera_get_view_x(view_camera[0]) + 529) && (mouse_y >= camera_get_view_y(view_camera[0]) + 234) && (mouse_x < camera_get_view_x(view_camera[0]) + 611) && (mouse_y < camera_get_view_y(view_camera[0]) + 249)) { - if (instance_exists(obj_star_select)) { - if (obj_star_select.button1 != "") { + if (obj_controller.selecting_planet > 0 && instance_exists(obj_star_select)) { + var _btn_count = array_length(obj_star_select.buttons); + for (var i = 0; i < _btn_count; i++) { + if ((mouse_x >= camera_get_view_x(view_camera[0]) + 529) && (mouse_y >= camera_get_view_y(view_camera[0]) + 234 + (16 * i)) && (mouse_x < camera_get_view_x(view_camera[0]) + 611) && (mouse_y < camera_get_view_y(view_camera[0]) + 249 + (16 * i))) { within = 0; } } } - if ((mouse_x >= camera_get_view_x(view_camera[0]) + 529) && (mouse_y >= camera_get_view_y(view_camera[0]) + 234 + 16) && (mouse_x < camera_get_view_x(view_camera[0]) + 611) && (mouse_y < camera_get_view_y(view_camera[0]) + 249 + 16)) { - if (instance_exists(obj_star_select)) { - if (obj_star_select.button2 != "") { - within = 0; - } - } - } - if ((mouse_x >= camera_get_view_x(view_camera[0]) + 529) && (mouse_y >= camera_get_view_y(view_camera[0]) + 234 + 32) && (mouse_x < camera_get_view_x(view_camera[0]) + 611) && (mouse_y < camera_get_view_y(view_camera[0]) + 249 + 32)) { - if (instance_exists(obj_star_select)) { - if (obj_star_select.button3 != "") { - within = 0; - } - } - } -} var line_width = sqr(scale); var text_size = sqr(scale); diff --git a/objects/obj_star_select/Create_0.gml b/objects/obj_star_select/Create_0.gml index 99db0584e..1091b1480 100644 --- a/objects/obj_star_select/Create_0.gml +++ b/objects/obj_star_select/Create_0.gml @@ -80,17 +80,9 @@ recruitment_costup_button.bind_method = function() { }; buttons_selected = false; -button1 = ""; -button2 = ""; -button3 = ""; -button4 = ""; -button5 = ""; +buttons = []; +shutters = []; button_manager = new UnitButtonObject(); -shutter_1 = new ShutterButton(); -shutter_2 = new ShutterButton(); -shutter_3 = new ShutterButton(); -shutter_4 = new ShutterButton(); -shutter_5 = new ShutterButton(); attack = 0; raid = 0; bombard = 0; diff --git a/objects/obj_star_select/Draw_64.gml b/objects/obj_star_select/Draw_64.gml index eb2b02373..0ff04a153 100644 --- a/objects/obj_star_select/Draw_64.gml +++ b/objects/obj_star_select/Draw_64.gml @@ -21,10 +21,7 @@ draw_set_color(0); try { if (loading == 1) { obj_controller.selecting_planet = 0; - button1 = ""; - button2 = ""; - button3 = ""; - button4 = ""; + buttons = []; if (instance_exists(target)) { if (target.space_hulk == 1) { @@ -60,13 +57,7 @@ try { } } } - var shutters = [ - shutter_1, - shutter_2, - shutter_3, - shutter_4 - ]; - for (var i = 0; i < 4; i++) { + for (var i = 0; i < array_length(shutters); i++) { var shutter_button = shutters[i]; if (shutter_button.hit()) { closes = false; @@ -151,62 +142,52 @@ try { if (p_data.planet != _planet) { p_data = target.get_planet_data(_planet); } + // Buttons that are available if (!buttons_selected) { - var is_enemy = false; - if ((obj_controller.faction_status[eFACTION.IMPERIUM] != "War" && p_data.current_owner > 5) || (obj_controller.faction_status[eFACTION.IMPERIUM] == "War" && p_data.at_war(0, 1, 1) && p_data.player_disposition <= 50)) { - is_enemy = true; - } + buttons = []; if (p_data.planet > 0) { - if (target.present_fleet[1] == 0) { - if (p_data.player_forces > 0) { - if (is_enemy) { - button1 = "Attack"; - if (p_data.population) { - button2 = "Purge"; - } - } - } - } if (target.present_fleet[1] > 0) { - button1 = "Attack"; - button2 = "Raid"; - if (is_enemy || p_data.xenos_and_heretics() > 0) { - button3 = "Bombard"; - } else if (p_data.population > 0) { - button3 = "Purge"; + if (p_data.has_any_force()) { + array_push(buttons, "Attack", "Raid", "Bombard"); + } + + if (p_data.population > 0) { + array_push(buttons, "Purge"); } if (torpedo > 0) { var pfleet = instance_nearest(x, y, obj_p_fleet); if (instance_exists(pfleet) && (point_distance(pfleet.x, pfleet.y, target.x, target.y) <= 40) && (pfleet.action == "")) { - if ((pfleet.capital_number + pfleet.frigate_number > 0) && (button4 == "")) { - button4 = "Cyclonic Torpedo"; + if (pfleet.capital_number + pfleet.frigate_number > 0) { + array_push(buttons, "Cyclonic Torpedo"); } } } + } else if (p_data.player_forces > 0) { + if (p_data.has_any_force()) { + array_push(buttons, "Attack"); + } + + if (p_data.population > 0) { + array_push(buttons, "Purge"); + } } } var planet_upgrades = target.p_upgrades[obj_controller.selecting_planet]; if (((p_data.planet_type == "Dead") || (array_length(p_data.upgrades) > 0)) && ((target.present_fleet[1] > 0) || (target.p_player[obj_controller.selecting_planet] > 0))) { if ((array_length(p_data.features) == 0) || (array_length(planet_upgrades) > 0)) { - chock = !p_data.xenos_and_heretics(); - if (chock == 1) { - if (p_data.has_upgrade(eP_FEATURES.SECRET_BASE)) { - button1 = "Base"; + if (!p_data.has_enemy_force()) { + buttons = []; + if (array_length(p_data.upgrades) == 0) { + array_push(buttons, "Build"); + } else if (p_data.has_upgrade(eP_FEATURES.SECRET_BASE)) { + array_push(buttons, "Base"); } else if (p_data.has_upgrade(eP_FEATURES.ARSENAL)) { - button1 = "Arsenal"; + array_push(buttons, "Arsenal"); } else if (p_data.has_upgrade(eP_FEATURES.GENE_VAULT)) { - button1 = "Gene-Vault"; - } else if (array_length(p_data.upgrades) == 0) { - button1 = "Build"; - } - if (array_contains(["Build", "Gene-Vault", "Arsenal", "Base"], button1)) { - button2 = ""; - button3 = ""; - button4 = ""; - button5 = ""; + array_push(buttons, "Gene-Vault"); } } } @@ -214,17 +195,23 @@ try { if (obj_controller.recruiting_worlds_bought > 0 && !p_data.at_war()) { if (!p_data.has_feature(eP_FEATURES.RECRUITING_WORLD) && p_data.planet_type != "Dead" && !target.space_hulk) { - button4 = "+Recruiting"; + array_push(buttons, "+Recruiting"); } } if (target.space_hulk) { if (target.present_fleet[1] > 0) { - button1 = "Raid"; - button2 = "Bombard"; - button3 = ""; - button4 = ""; + buttons = ["Raid", "Bombard"]; } } + + while (array_length(shutters) < array_length(buttons)) { + array_push(shutters, new ShutterButton()); + } + + while (array_length(shutters) > array_length(buttons)) { + array_delete(shutters, array_length(shutters) - 1, 1); + } + buttons_selected = true; } @@ -293,17 +280,10 @@ try { var shutter_x = main_data_slate.XX - 165; var shutter_y = 296 + 165; if (!debug) { - if (shutter_1.draw_shutter(shutter_x, shutter_y, button1, 0.5, true)) { - current_button = button1; - } - if (shutter_2.draw_shutter(shutter_x, shutter_y + 47, button2, 0.5, true)) { - current_button = button2; - } - if (shutter_3.draw_shutter(shutter_x, shutter_y + (47 * 2), button3, 0.5, true)) { - current_button = button3; - } - if (shutter_4.draw_shutter(shutter_x, shutter_y + (47 * 3), button4, 0.5, true)) { - current_button = button4; + for (var i = 0; i < array_length(buttons); i++) { + if (shutters[i].draw_shutter(shutter_x, shutter_y + (47 * i), buttons[i], 0.5, true)) { + current_button = buttons[i]; + } } } if (current_button != "") { @@ -374,17 +354,9 @@ try { obj_controller.recruiting_worlds += planet_numeral_name(obj_controller.selecting_planet, target); } if (obj_controller.recruiting_worlds_bought == 0) { - if (button1 == "+Recruiting") { - button1 = ""; - } - if (button2 == "+Recruiting") { - button2 = ""; - } - if (button3 == "+Recruiting") { - button3 = ""; - } - if (button4 == "+Recruiting") { - button4 = ""; + var _idx = array_get_index(buttons, "+Recruiting"); + if (_idx > -1) { + array_delete(buttons, _idx, 1); } } // popup? diff --git a/scripts/scr_PlanetData/scr_PlanetData.gml b/scripts/scr_PlanetData/scr_PlanetData.gml index 6cabe180c..1e4ce27b8 100644 --- a/scripts/scr_PlanetData/scr_PlanetData.gml +++ b/scripts/scr_PlanetData/scr_PlanetData.gml @@ -805,7 +805,7 @@ function PlanetData(_planet, _system) constructor { }; static has_enemy_force = function() { - for (var i = 1; i < array_length(planet_forces); i++) { + for (var i = 2; i < array_length(planet_forces); i++) { if (planet_forces[i] > 0 && obj_controller.faction_status[i] == "War") { return true; } @@ -814,7 +814,7 @@ function PlanetData(_planet, _system) constructor { }; static has_any_force = function() { - for (var i = 1; i < array_length(planet_forces); i++) { + for (var i = 2; i < array_length(planet_forces); i++) { if (planet_forces[i] > 0) { return true; } diff --git a/scripts/scr_void_click/scr_void_click.gml b/scripts/scr_void_click/scr_void_click.gml index 46e1ba8ae..3349fce04 100644 --- a/scripts/scr_void_click/scr_void_click.gml +++ b/scripts/scr_void_click/scr_void_click.gml @@ -26,30 +26,11 @@ function scr_void_click() { } } else if (instance_exists(obj_star_select)) { if (obj_controller.selecting_planet > 0) { - // This prevents clicking onto a new star by pressing the buttons or planet panel - if (scr_hit(xx + (27 * scale), yy + (166 * scale), xx + (727 * scale), yy + (458 * scale))) { - if (obj_star_select.button1 != "") { - good = false; - } - } - if (scr_hit(xx + (348 * scale), yy + (461 * scale), xx + (348 * scale) + (246 * scale), yy + (461 * scale) + (26 * scale))) { - if (obj_star_select.button1 != "") { - good = false; - } - } - if (scr_hit(xx + (348 * scale), yy + (489 * scale), xx + (348 * scale) + (246 * scale), yy + (489 * scale) + (26 * scale))) { - if (obj_star_select.button2 != "") { - good = false; - } - } - if (scr_hit(xx + (348 * scale), yy + (517 * scale), xx + (348 * scale) + (246 * scale), yy + (517 * scale) + (26 * scale))) { - if (obj_star_select.button3 != "") { - good = false; - } - } - if (scr_hit(xx + (348 * scale), yy + (545 * scale), xx + (348 * scale) + (246 * scale), yy + (545 * scale) + (26 * scale))) { - if (obj_star_select.button4 != "") { + var _shutters = obj_star_select.shutters; + for (var i = 0; i < array_length(_shutters); i++) { + if (_shutters[i].hit()) { good = false; + break; } } } From a20fbe6bbbd064cf4ef98c11de16092e4aded2a0 Mon Sep 17 00:00:00 2001 From: EttyKitty <20323032+EttyKitty@users.noreply.github.com> Date: Fri, 10 Jul 2026 04:19:12 +0300 Subject: [PATCH 03/14] chore: Move two string functions --- .../scr_logging_functions.gml | 15 --------------- .../scr_string_functions/scr_string_functions.gml | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/scripts/scr_logging_functions/scr_logging_functions.gml b/scripts/scr_logging_functions/scr_logging_functions.gml index 56dfe6aa9..3de4e4244 100644 --- a/scripts/scr_logging_functions/scr_logging_functions.gml +++ b/scripts/scr_logging_functions/scr_logging_functions.gml @@ -3,21 +3,6 @@ exception_unhandled_handler(function(_exception) { return 0; }); -/// @desc Formats text as a code block. -/// @param {string} _message The message to format. -/// @param {string} _language (Optional) Code language prefix to add into the codeblock. -/// @returns {string} The formatted string. -function format_codeblock(_message, _language = "") { - return string_length(_message) > 0 ? $"```{_language}\n{_message}\n```" : ""; -} - -/// @desc Converts to string and adds a 0 at the start, if input is less than 10. -/// @param {real} _time - Usually hours, minutes or seconds. -/// @returns {string} -function format_time(_time) { - return (_time < 10) ? $"0{_time}" : string(_time); -} - /// @desc Removes all GM prefixes from a string. /// @param {string} _string /// @returns {string} diff --git a/scripts/scr_string_functions/scr_string_functions.gml b/scripts/scr_string_functions/scr_string_functions.gml index d0af0b475..0651560f6 100644 --- a/scripts/scr_string_functions/scr_string_functions.gml +++ b/scripts/scr_string_functions/scr_string_functions.gml @@ -489,3 +489,18 @@ function string_join_oxford_comma(_items) { } return _list; } + +/// @desc Formats text as a code block. +/// @param {string} _message The message to format. +/// @param {string} _language (Optional) Code language prefix to add into the codeblock. +/// @returns {string} The formatted string. +function format_codeblock(_message, _language = "") { + return string_length(_message) > 0 ? $"```{_language}\n{_message}\n```" : ""; +} + +/// @desc Converts to string and adds a 0 at the start, if input is less than 10. +/// @param {real} _time - Usually hours, minutes or seconds. +/// @returns {string} +function format_time(_time) { + return (_time < 10) ? $"0{_time}" : string(_time); +} From c58fe6f6a2992a079dde5572ed64548157a77d1e Mon Sep 17 00:00:00 2001 From: EttyKitty <20323032+EttyKitty@users.noreply.github.com> Date: Fri, 10 Jul 2026 04:34:13 +0300 Subject: [PATCH 04/14] chore: Move all helper libraries into a group --- ChapterMaster.yyp | 1 + scripts/scr_array_functions/scr_array_functions.yy | 4 ++-- .../scr_general_variable_functions.yy | 4 ++-- scripts/scr_ini_functions/scr_ini_functions.yy | 4 ++-- scripts/scr_json_functions/scr_json_functions.yy | 4 ++-- scripts/scr_logging_functions/scr_logging_functions.yy | 4 ++-- .../scr_serialization_functions.yy | 4 ++-- scripts/scr_sprite_functions/scr_sprite_functions.yy | 4 ++-- scripts/scr_string_functions/scr_string_functions.yy | 4 ++-- scripts/scr_struct_functions/scr_struct_functions.yy | 4 ++-- 10 files changed, 19 insertions(+), 18 deletions(-) diff --git a/ChapterMaster.yyp b/ChapterMaster.yyp index df4dcf603..2a59a5187 100644 --- a/ChapterMaster.yyp +++ b/ChapterMaster.yyp @@ -32,6 +32,7 @@ {"$GMFolder":"","%Name":"Diplomacy","folderPath":"folders/Scripts/Diplomacy.yy","name":"Diplomacy","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"events_and_missions","folderPath":"folders/Scripts/events_and_missions.yy","name":"events_and_missions","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"fleet","folderPath":"folders/Scripts/fleet.yy","name":"fleet","resourceType":"GMFolder","resourceVersion":"2.0",}, + {"$GMFolder":"","%Name":"Global Functions","folderPath":"folders/Scripts/Global Functions.yy","name":"Global Functions","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"Helpers","folderPath":"folders/Scripts/Helpers.yy","name":"Helpers","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"Draw Shapes","folderPath":"folders/Scripts/Helpers/Draw Shapes.yy","name":"Draw Shapes","resourceType":"GMFolder","resourceVersion":"2.0",}, {"$GMFolder":"","%Name":"Text","folderPath":"folders/Scripts/Helpers/Text.yy","name":"Text","resourceType":"GMFolder","resourceVersion":"2.0",}, diff --git a/scripts/scr_array_functions/scr_array_functions.yy b/scripts/scr_array_functions/scr_array_functions.yy index a0b99b336..e9d39d229 100644 --- a/scripts/scr_array_functions/scr_array_functions.yy +++ b/scripts/scr_array_functions/scr_array_functions.yy @@ -5,8 +5,8 @@ "isDnD":false, "name":"scr_array_functions", "parent":{ - "name":"Sys", - "path":"folders/Scripts/Sys.yy", + "name":"Global Functions", + "path":"folders/Scripts/Global Functions.yy", }, "resourceType":"GMScript", "resourceVersion":"2.0", diff --git a/scripts/scr_general_variable_functions/scr_general_variable_functions.yy b/scripts/scr_general_variable_functions/scr_general_variable_functions.yy index f968da392..a2edd20db 100644 --- a/scripts/scr_general_variable_functions/scr_general_variable_functions.yy +++ b/scripts/scr_general_variable_functions/scr_general_variable_functions.yy @@ -5,8 +5,8 @@ "isDnD":false, "name":"scr_general_variable_functions", "parent":{ - "name":"Scripts", - "path":"folders/Scripts.yy", + "name":"Global Functions", + "path":"folders/Scripts/Global Functions.yy", }, "resourceType":"GMScript", "resourceVersion":"2.0", diff --git a/scripts/scr_ini_functions/scr_ini_functions.yy b/scripts/scr_ini_functions/scr_ini_functions.yy index ad6c23231..098d93202 100644 --- a/scripts/scr_ini_functions/scr_ini_functions.yy +++ b/scripts/scr_ini_functions/scr_ini_functions.yy @@ -5,8 +5,8 @@ "isDnD":false, "name":"scr_ini_functions", "parent":{ - "name":"Scripts", - "path":"folders/Scripts.yy", + "name":"Global Functions", + "path":"folders/Scripts/Global Functions.yy", }, "resourceType":"GMScript", "resourceVersion":"2.0", diff --git a/scripts/scr_json_functions/scr_json_functions.yy b/scripts/scr_json_functions/scr_json_functions.yy index e8d07c8b9..7969d4cea 100644 --- a/scripts/scr_json_functions/scr_json_functions.yy +++ b/scripts/scr_json_functions/scr_json_functions.yy @@ -5,8 +5,8 @@ "isDnD":false, "name":"scr_json_functions", "parent":{ - "name":"Scripts", - "path":"folders/Scripts.yy", + "name":"Global Functions", + "path":"folders/Scripts/Global Functions.yy", }, "resourceType":"GMScript", "resourceVersion":"2.0", diff --git a/scripts/scr_logging_functions/scr_logging_functions.yy b/scripts/scr_logging_functions/scr_logging_functions.yy index b4dc5cfc0..80998932b 100644 --- a/scripts/scr_logging_functions/scr_logging_functions.yy +++ b/scripts/scr_logging_functions/scr_logging_functions.yy @@ -5,8 +5,8 @@ "isDnD":false, "name":"scr_logging_functions", "parent":{ - "name":"Scripts", - "path":"folders/Scripts.yy", + "name":"Global Functions", + "path":"folders/Scripts/Global Functions.yy", }, "resourceType":"GMScript", "resourceVersion":"2.0", diff --git a/scripts/scr_serialization_functions/scr_serialization_functions.yy b/scripts/scr_serialization_functions/scr_serialization_functions.yy index 15357345d..e9790d571 100644 --- a/scripts/scr_serialization_functions/scr_serialization_functions.yy +++ b/scripts/scr_serialization_functions/scr_serialization_functions.yy @@ -5,8 +5,8 @@ "isDnD":false, "name":"scr_serialization_functions", "parent":{ - "name":"Scripts", - "path":"folders/Scripts.yy", + "name":"Global Functions", + "path":"folders/Scripts/Global Functions.yy", }, "resourceType":"GMScript", "resourceVersion":"2.0", diff --git a/scripts/scr_sprite_functions/scr_sprite_functions.yy b/scripts/scr_sprite_functions/scr_sprite_functions.yy index d1706b777..66eaab2bb 100644 --- a/scripts/scr_sprite_functions/scr_sprite_functions.yy +++ b/scripts/scr_sprite_functions/scr_sprite_functions.yy @@ -5,8 +5,8 @@ "isDnD":false, "name":"scr_sprite_functions", "parent":{ - "name":"Scripts", - "path":"folders/Scripts.yy", + "name":"Global Functions", + "path":"folders/Scripts/Global Functions.yy", }, "resourceType":"GMScript", "resourceVersion":"2.0", diff --git a/scripts/scr_string_functions/scr_string_functions.yy b/scripts/scr_string_functions/scr_string_functions.yy index 2a39096ac..3762d1d41 100644 --- a/scripts/scr_string_functions/scr_string_functions.yy +++ b/scripts/scr_string_functions/scr_string_functions.yy @@ -5,8 +5,8 @@ "isDnD":false, "name":"scr_string_functions", "parent":{ - "name":"Text", - "path":"folders/Scripts/Helpers/Text.yy", + "name":"Global Functions", + "path":"folders/Scripts/Global Functions.yy", }, "resourceType":"GMScript", "resourceVersion":"2.0", diff --git a/scripts/scr_struct_functions/scr_struct_functions.yy b/scripts/scr_struct_functions/scr_struct_functions.yy index 9ac0d0e6e..eec59ca88 100644 --- a/scripts/scr_struct_functions/scr_struct_functions.yy +++ b/scripts/scr_struct_functions/scr_struct_functions.yy @@ -5,8 +5,8 @@ "isDnD":false, "name":"scr_struct_functions", "parent":{ - "name":"Scripts", - "path":"folders/Scripts.yy", + "name":"Global Functions", + "path":"folders/Scripts/Global Functions.yy", }, "resourceType":"GMScript", "resourceVersion":"2.0", From 1fb7ff81709c17fba8719c06086b4450821f77dc Mon Sep 17 00:00:00 2001 From: EttyKitty <20323032+EttyKitty@users.noreply.github.com> Date: Fri, 10 Jul 2026 05:07:11 +0300 Subject: [PATCH 05/14] fix: arrays_to_string_with_counts Continue during looping was causing trailing commas. --- scripts/scr_array_functions/scr_array_functions.gml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/scr_array_functions/scr_array_functions.gml b/scripts/scr_array_functions/scr_array_functions.gml index 806d25e08..b64b4ad02 100644 --- a/scripts/scr_array_functions/scr_array_functions.gml +++ b/scripts/scr_array_functions/scr_array_functions.gml @@ -189,13 +189,23 @@ function array_to_string_order(_strings_array, _use_and = false, _dot_end = true function arrays_to_string_with_counts(_names_array, _counts_array, _exclude_null = false, _dot_end = true) { var _array_length = array_length(_names_array); var _result_string = ""; + var _added_count = 0; for (var i = 0; i < _array_length; i++) { if (_exclude_null && _counts_array[i] == 0) { continue; } + + if (_added_count > 0) { + _result_string += ", "; + } + _result_string += string_plural_count(_names_array[i], _counts_array[i]); - _result_string += smart_delimeter_sign(_array_length, i, _dot_end); + _added_count++; + } + + if (_dot_end && _added_count > 0) { + _result_string += "."; } return _result_string; From 9989c4a06972568e6917adc54ea7eb52be455e1f Mon Sep 17 00:00:00 2001 From: EttyKitty <20323032+EttyKitty@users.noreply.github.com> Date: Fri, 10 Jul 2026 05:14:34 +0300 Subject: [PATCH 06/14] refactor: Add CombatDebugger class --- ChapterMaster.yyp | 1 + scripts/CombatDebugger/CombatDebugger.gml | 150 ++++++++++++++++++++++ scripts/CombatDebugger/CombatDebugger.yy | 13 ++ 3 files changed, 164 insertions(+) create mode 100644 scripts/CombatDebugger/CombatDebugger.gml create mode 100644 scripts/CombatDebugger/CombatDebugger.yy diff --git a/ChapterMaster.yyp b/ChapterMaster.yyp index 2a59a5187..a3f53266c 100644 --- a/ChapterMaster.yyp +++ b/ChapterMaster.yyp @@ -716,6 +716,7 @@ {"id":{"name":"Armamentarium","path":"scripts/Armamentarium/Armamentarium.yy",},}, {"id":{"name":"ColourItem","path":"scripts/ColourItem/ColourItem.yy",},}, {"id":{"name":"ColourPicker","path":"scripts/ColourPicker/ColourPicker.yy",},}, + {"id":{"name":"CombatDebugger","path":"scripts/CombatDebugger/CombatDebugger.yy",},}, {"id":{"name":"CombatLog","path":"scripts/CombatLog/CombatLog.yy",},}, {"id":{"name":"DebugView","path":"scripts/DebugView/DebugView.yy",},}, {"id":{"name":"DiploBasicNodes","path":"scripts/DiploBasicNodes/DiploBasicNodes.yy",},}, diff --git a/scripts/CombatDebugger/CombatDebugger.gml b/scripts/CombatDebugger/CombatDebugger.gml new file mode 100644 index 000000000..3b5bc0dbb --- /dev/null +++ b/scripts/CombatDebugger/CombatDebugger.gml @@ -0,0 +1,150 @@ +enum eCOMBAT_CATEGORY { + SYSTEM, + TARGETING, + SHOOTING, + DAMAGE, + CLEANUP, + __COUNT, +} + +// TODO: Convert this into a BufferedFileWriter or BufferedFileLogger, decoupling from specific combat logic; Then maybe even use in the Logger class for 0 I/O overhead; +/// @description Buffers structured combat debug entries directly to memory and dumps them to a log file. +/// @param {Bool} _active Whether this debugger starts active (default: false) +function CombatDebugger(_active = false) constructor { + active = _active; + + categories = array_create(eCOMBAT_CATEGORY.__COUNT, true); + + __log_buffer = buffer_create(16384, buffer_grow, 1); + + static category_names = [ + "SYSTEM", + "TARGETING", + "SHOOTING", + "DAMAGE", + "CLEANUP", + ]; + + /// @description Writes a single line to the given buffer. + /// @param {Id.Buffer} _buf + /// @param {String} _str + static __write_line = function(_buf, _str) { + buffer_write(_buf, buffer_text, _str + "\n"); + }; + + /// @description Add a debug entry to the buffer. + /// @param {Enum.eCOMBAT_CATEGORY} _category Message prefix + /// @param {String} _message The message to log + static add = function(_category, _message) { + if (!active) { + return self; + } + + if (_category < 0 || _category >= eCOMBAT_CATEGORY.__COUNT) { + return self; + } + + var _enabled = categories[_category]; + if (!_enabled) { + return self; + } + + var _cat_name = category_names[_category]; + + var _time = $"{format_time(current_hour)}:{format_time(current_minute)}:{format_time(current_second)}"; + var _line = $"{_time} | [{_cat_name}] {_message}\n"; + + buffer_write(__log_buffer, buffer_text, _line); + + return self; + }; + + /// @description Returns a short human-readable label for a combat instance. + /// @param {Id.Instance.obj_pnunit|Id.Instance.obj_enunit} _inst The instance or value to label. + /// @returns {String} + static resolve_label = function(_inst) { + if (!instance_exists(_inst)) { + return string(_inst); + } + + var _object_index = _inst.object_index; + + if (_object_index == obj_nfort) { + return "Fort"; + } + + if (_object_index != obj_pnunit && _object_index != obj_enunit) { + return $"inst({_inst.id})"; + } + + var _desc = arrays_to_string_with_counts(_inst.dudes, _inst.dudes_num, true, false); + return $"<{_desc}>"; + }; + + /// @description Writes to disk, and resets. + /// @param {Struct} _battle_info Optional battle info struct to include in the header + static flush = function(_battle_info = undefined) { + if (!buffer_exists(__log_buffer)) { + return self; + } + + var _log_size = buffer_tell(__log_buffer); + if (_log_size == 0) { + reset(); + return self; + } + + var _date_str = $"{current_year}-{format_time(current_month)}-{format_time(current_day)}"; + var _time_str = $"{format_time(current_hour)}{format_time(current_minute)}{format_time(current_second)}"; + var _filename = $"{PATH_LOG_DIRECTORY}combat_debug_{_date_str}_{_time_str}.log"; + + var _final_buffer = buffer_create(_log_size + 1024, buffer_grow, 1); + + __write_line(_final_buffer, "=== COMBAT DEBUG LOG ==="); + __write_line(_final_buffer, $"Date: {date_datetime_string(date_current_datetime())}"); + + if (is_struct(_battle_info)) { + var _keys = variable_struct_get_names(_battle_info); + var _len = array_length(_keys); + for (var i = 0; i < _len; i++) { + var _key = _keys[i]; + __write_line(_final_buffer, $"{_key}: {_battle_info[$ _key]}"); + } + } + + __write_line(_final_buffer, "========================================"); + __write_line(_final_buffer, ""); + + var _dest_offset = buffer_tell(_final_buffer); + buffer_copy(__log_buffer, 0, _log_size, _final_buffer, _dest_offset); + + buffer_seek(_final_buffer, buffer_seek_start, _dest_offset + _log_size); + __write_line(_final_buffer, "\n=== END OF COMBAT DEBUG LOG ==="); + + buffer_save_ext(_final_buffer, _filename, 0, buffer_tell(_final_buffer)); + buffer_delete(_final_buffer); + + reset(); + + return self; + }; + + /// @description Rewind the buffer pointer, resetting state. + static reset = function() { + if (buffer_exists(__log_buffer)) { + buffer_seek(__log_buffer, buffer_seek_start, 0); + } + + return self; + }; + + /// @description MUST be called when destroying this struct to prevent memory leaks. + static cleanup = function() { + if (buffer_exists(__log_buffer)) { + buffer_delete(__log_buffer); + __log_buffer = -1; + } + + return self; + }; +} diff --git a/scripts/CombatDebugger/CombatDebugger.yy b/scripts/CombatDebugger/CombatDebugger.yy new file mode 100644 index 000000000..bbda44371 --- /dev/null +++ b/scripts/CombatDebugger/CombatDebugger.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"v1", + "%Name":"CombatDebugger", + "isCompatibility":false, + "isDnD":false, + "name":"CombatDebugger", + "parent":{ + "name":"Constructors", + "path":"folders/Scripts/Constructors.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file From 7ca2acacf8d419faec5914cd1cc1b5684e26bd97 Mon Sep 17 00:00:00 2001 From: EttyKitty <20323032+EttyKitty@users.noreply.github.com> Date: Fri, 10 Jul 2026 05:17:40 +0300 Subject: [PATCH 07/14] refactor: Wire-in CombatDebugger (test) --- objects/obj_enunit/Alarm_0.gml | 37 +++++++++++++++++--- objects/obj_ncombat/Alarm_7.gml | 10 ++++++ objects/obj_ncombat/CleanUp_0.gml | 1 + objects/obj_ncombat/Create_0.gml | 3 ++ objects/obj_ncombat/KeyPress_13.gml | 2 ++ objects/obj_ncombat/obj_ncombat.yy | 1 + objects/obj_pnunit/Alarm_0.gml | 53 +++++++++++++++++++---------- scripts/scr_clean/scr_clean.gml | 18 ++++++++++ 8 files changed, 103 insertions(+), 22 deletions(-) create mode 100644 objects/obj_ncombat/CleanUp_0.gml diff --git a/objects/obj_enunit/Alarm_0.gml b/objects/obj_enunit/Alarm_0.gml index 4cd0a2b99..644b3f362 100644 --- a/objects/obj_enunit/Alarm_0.gml +++ b/objects/obj_enunit/Alarm_0.gml @@ -1,18 +1,25 @@ /// @description This alarm is responsible for the enemy target column selection +obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.SYSTEM, $"Enemy {obj_ncombat.combat_debugger.resolve_label(id)} at x={x}, flank={flank} is picking a target"); + if (!instance_exists(obj_pnunit)) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"No valid player blocks, exiting"); exit; } enemy = flank ? get_leftmost() : get_rightmost(); if (enemy == noone) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"Couldn't find valid player blocks, exiting"); exit; } +obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"Initial target player block: {obj_ncombat.combat_debugger.resolve_label(enemy)} at x={enemy.x}"); + //In melee check engaged = collision_point(x - 10, y, obj_pnunit, 0, 1) || collision_point(x + 10, y, obj_pnunit, 0, 1); if (!engaged) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"Not engaged, firing"); // Shooting for (var i = 0; i < array_length(wep); i++) { if (wep[i] == "" || wep_num[i] == 0) { @@ -23,6 +30,8 @@ if (!engaged) { continue; } + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"{wep[i]}(i{i}) is firing"); + if (range[i] == 0) { LOGGER.error($"{wep[i]} has broken range! This shouldn't happen! Range: {range[i]}; Ammo: {ammo[i]}; Owner: {wep_owner[i]}"); continue; @@ -30,7 +39,9 @@ if (!engaged) { if (!target_block_is_valid(enemy, obj_pnunit)) { enemy = flank == 0 ? get_rightmost() : get_leftmost(); + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"Target is invalid, flipped to {obj_ncombat.combat_debugger.resolve_label(enemy)}"); if (!target_block_is_valid(enemy, obj_pnunit)) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"Target is still invalid, exiting"); exit; } } @@ -40,6 +51,7 @@ if (!engaged) { if (instance_exists(obj_nfort) && !flank) { enemy = instance_nearest(x, y, obj_nfort); dist = 2; + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"Targeting Fort"); } else { dist = get_block_distance(enemy); } @@ -69,6 +81,7 @@ if (!engaged) { if (cm_present) { enemy = cm_block; target_unit_index = cm_index; + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"Alpha Strike: targeting Chapter Master at {obj_ncombat.combat_debugger.resolve_label(cm_block)} unit_index={cm_index}"); } } @@ -78,6 +91,7 @@ if (!engaged) { var _shot = false; if ((!instance_exists(obj_nfort)) || flank) { if (block_has_armour(enemy) || (enemy.veh_type[1] == "Defenses")) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"AP -> vehicle in column {obj_ncombat.combat_debugger.resolve_label(enemy)}, apa={apa[i]}, firing"); scr_shoot(i, enemy, target_unit_index, "arp", "ranged"); continue; } else if ((instance_number(obj_pnunit) > 1)) { @@ -92,6 +106,7 @@ if (!engaged) { break; } if (block_has_armour(enemy2)) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"AP -> vehicle found in next column {obj_ncombat.combat_debugger.resolve_label(enemy2)}, firing"); scr_shoot(i, enemy2, target_unit_index, "arp", "ranged"); _shot = true; break; @@ -100,10 +115,12 @@ if (!engaged) { if (!_shot) { _no_vehicles_present = true; _target_vehicles = false; + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"AP -> no vehicles found, falling back to infantry"); } } } else { enemy = instance_nearest(x, y, obj_nfort); + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"AP -> targeting wall"); scr_shoot(i, enemy, 1, "arp", "wall"); continue; } @@ -113,7 +130,7 @@ if (!engaged) { if ((!_target_vehicles) && ((!instance_exists(obj_nfort)) || flank)) { var _shot = false; if (enemy.men > 0) { - // There are marines in the first column; + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"non-AP -> infantry in column {obj_ncombat.combat_debugger.resolve_label(enemy)}, men={enemy.men}, firing"); scr_shoot(i, enemy, target_unit_index, "att", "ranged"); continue; } else if (instance_number(obj_pnunit) > 1) { @@ -144,6 +161,7 @@ if (!engaged) { continue; } } + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"non-AP -> infantry found in back column {obj_ncombat.combat_debugger.resolve_label(enemy2)}, firing"); scr_shoot(i, enemy2, target_unit_index, "att", "ranged"); _shot = true; break; @@ -155,6 +173,7 @@ if (!engaged) { if (!_shot && !_no_vehicles_present) { if ((!instance_exists(obj_nfort)) || flank) { if (block_has_armour(enemy) || (enemy.veh_type[1] == "Defenses")) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"non-AP fallback -> armour in column {obj_ncombat.combat_debugger.resolve_label(enemy)}, firing"); scr_shoot(i, enemy, target_unit_index, "att", "ranged"); continue; } else if ((instance_number(obj_pnunit) > 1)) { @@ -169,6 +188,7 @@ if (!engaged) { break; } if (block_has_armour(enemy2)) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"non-AP fallback -> armour in next column {obj_ncombat.combat_debugger.resolve_label(enemy2)}, firing"); scr_shoot(i, enemy2, target_unit_index, "att", "ranged"); break; } @@ -176,6 +196,7 @@ if (!engaged) { } } else { enemy = instance_nearest(x, y, obj_nfort); + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"non-AP -> targeting fort, firing"); scr_shoot(i, enemy, 1, "att", "wall"); continue; } @@ -187,6 +208,7 @@ if (!engaged) { LOGGER.error($"{wep[i]} didn't find a valid target! This shouldn't happen!"); } } else if ((engaged || enemy.engaged) && target_block_is_valid(enemy, obj_pnunit)) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"Engaged, attacking in melee"); //TODO: The melee code was not refactored; // Melee engaged = 1; @@ -208,13 +230,16 @@ if (!engaged) { } if ((range[i] <= 2) || (floor(range[i]) != range[i])) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"{wep[i]}(i{i}) is striking"); // Weapon meets preliminary checks if (apa[i] > 2) { _armour_piercing = true; - } // Determines if it is _armour_piercing or not + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"melee AP=true"); + } if (_armour_piercing && instance_exists(obj_nfort) && (!flank)) { // Huff and puff and blow the wall down enemy = instance_nearest(x, y, obj_nfort); + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"melee AP -> wall"); scr_shoot(i, enemy, 1, "arp", "wall"); continue; } @@ -223,20 +248,24 @@ if (!engaged) { var good = false; if (block_has_armour(enemy)) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"melee AP -> vehicles in {obj_ncombat.combat_debugger.resolve_label(enemy)}"); scr_shoot(i, enemy, 1, "arp", "melee"); good = true; } if (!good) { _armour_piercing = false; - } // Fuck it, shoot at infantry + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"melee AP -> no vehicles, falling back to infantry"); + } } if ((!_armour_piercing) && target_block_is_valid(enemy, obj_pnunit)) { // Check for men if (enemy.men) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"melee -> infantry in {obj_ncombat.combat_debugger.resolve_label(enemy)}"); scr_shoot(i, enemy, 1, "att", "melee"); } else if (block_has_armour(enemy)) { - scr_shoot(i, enemy, 1, "arp", "melee"); // Swing anyways, maybe they'll get lucky + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"melee -> armour fallback in {obj_ncombat.combat_debugger.resolve_label(enemy)}"); + scr_shoot(i, enemy, 1, "arp", "melee"); } } } diff --git a/objects/obj_ncombat/Alarm_7.gml b/objects/obj_ncombat/Alarm_7.gml index 962ebc540..7f5fc458a 100644 --- a/objects/obj_ncombat/Alarm_7.gml +++ b/objects/obj_ncombat/Alarm_7.gml @@ -550,6 +550,16 @@ try { obj_cursor.image_index = 0; } + if (combat_debugger.active) { + combat_debugger.flush({ + enemy_name: enem, + defeat: defeat, + turns: turn_count, + player_start: player_max, + player_end: player_forces, + }); + } + instance_destroy(); } catch (_exception) { ERROR_HANDLER.handle_exception(_exception); diff --git a/objects/obj_ncombat/CleanUp_0.gml b/objects/obj_ncombat/CleanUp_0.gml new file mode 100644 index 000000000..cfd7e0206 --- /dev/null +++ b/objects/obj_ncombat/CleanUp_0.gml @@ -0,0 +1 @@ +combat_debugger.cleanup(); diff --git a/objects/obj_ncombat/Create_0.gml b/objects/obj_ncombat/Create_0.gml index 1867d552e..4838aa1eb 100644 --- a/objects/obj_ncombat/Create_0.gml +++ b/objects/obj_ncombat/Create_0.gml @@ -174,6 +174,9 @@ dead_jims = 0; combat_log = new CombatLog(id); combat_log.log_font = fnt_aldrich_12; + +combat_debugger = new CombatDebugger(false); + ctally_target = undefined; ctally_bounce = []; ctally_injure = []; diff --git a/objects/obj_ncombat/KeyPress_13.gml b/objects/obj_ncombat/KeyPress_13.gml index a3e5cc56c..a8dc845ca 100644 --- a/objects/obj_ncombat/KeyPress_13.gml +++ b/objects/obj_ncombat/KeyPress_13.gml @@ -75,6 +75,7 @@ if (!instance_exists(obj_popup)) { } if ((timer_stage == 1) || (timer_stage == 5)) { + combat_debugger.add(eCOMBAT_CATEGORY.SYSTEM, $"=== Player Turn start (turn {turn_count}) ==="); if (global_perils > 0) { global_perils -= 1; } @@ -105,6 +106,7 @@ if (!instance_exists(obj_popup)) { reset_combat_message_arrays(); timer_stage = 2; } else if (timer_stage == 3) { + combat_debugger.add(eCOMBAT_CATEGORY.SYSTEM, $"=== Enemy Turn start (turn {turn_count}) ==="); if (battle_over != 1) { alarm[8] = 15; } diff --git a/objects/obj_ncombat/obj_ncombat.yy b/objects/obj_ncombat/obj_ncombat.yy index 538bdd0f5..5476e7636 100644 --- a/objects/obj_ncombat/obj_ncombat.yy +++ b/objects/obj_ncombat/obj_ncombat.yy @@ -17,6 +17,7 @@ {"$GMEvent":"v1","%Name":"","collisionObjectId":null,"eventNum":67,"eventType":9,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, {"$GMEvent":"v1","%Name":"","collisionObjectId":null,"eventNum":13,"eventType":9,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, {"$GMEvent":"v1","%Name":"","collisionObjectId":null,"eventNum":64,"eventType":8,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, + {"$GMEvent":"v1","%Name":"","collisionObjectId":null,"eventNum":0,"eventType":12,"isDnD":false,"name":"","resourceType":"GMEvent","resourceVersion":"2.0",}, ], "managed":true, "name":"obj_ncombat", diff --git a/objects/obj_pnunit/Alarm_0.gml b/objects/obj_pnunit/Alarm_0.gml index a10457062..61aac367c 100644 --- a/objects/obj_pnunit/Alarm_0.gml +++ b/objects/obj_pnunit/Alarm_0.gml @@ -1,11 +1,15 @@ try { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.SYSTEM, $"Player block {obj_ncombat.combat_debugger.resolve_label(id)} at x={x} is picking a target"); enemy = instance_nearest(0, y, obj_enunit); // Left most enemy if (!instance_exists(enemy)) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"no enemy exists, exiting"); engaged = false; exit; } + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"initial target {obj_ncombat.combat_debugger.resolve_label(enemy)} at x={enemy.x}"); + if (instance_number(obj_enunit) != 1) { obj_ncombat.flank_x = self.x; with (obj_enunit) { @@ -118,9 +122,11 @@ try { } if ((ap == 1) && (once_only == 0)) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"weapon[{i}] ({wep[i]}) AP -> targeting vehicles"); // Check for vehicles if (enemy.veh > 0) { - good = scr_target(enemy, "veh"); // First target has vehicles, blow it to hell + good = scr_target(enemy, "veh"); + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"weapon[{i}] scr_target(veh) -> {enemy.dudes_vehicle[good]} in {obj_ncombat.combat_debugger.resolve_label(enemy)}"); scr_shoot(i, enemy, good, "arp", "ranged"); } if ((good == 0) && (instance_number(obj_enunit) > 1)) { @@ -131,7 +137,8 @@ try { x2 += 10; var enemy2 = instance_nearest(x2, y, obj_enunit); if ((enemy2.veh > 0) && (good == 0)) { - good = scr_target(enemy2, "veh"); // This target has vehicles, blow it to hell + good = scr_target(enemy2, "veh"); + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"weapon[{i}] scr_target(veh) at next column -> {enemy2.dudes_vehicle[good]} in {obj_ncombat.combat_debugger.resolve_label(enemy2)}"); scr_shoot(i, enemy2, good, "arp", "ranged"); once_only = 1; } @@ -140,7 +147,8 @@ try { } if (good == 0) { ap = 0; - } // Fuck it, shoot at infantry + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"weapon[{i}] ({wep[i]}) AP -> no vehicles found, falling back to infantry"); + } if (!instance_exists(enemy)) { engaged = false; continue; @@ -149,18 +157,20 @@ try { if (once_only == 0) { if ((enemy.medi > 0) && (enemy.veh == 0)) { - good = scr_target(enemy, "medi"); // First target has vehicles, blow it to hell + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"weapon[{i}] ({wep[i]}) medi -> targeting monsters"); + good = scr_target(enemy, "medi"); + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"weapon[{i}] scr_target(medi) -> {enemy.dudes[good]} in {obj_ncombat.combat_debugger.resolve_label(enemy)}"); scr_shoot(i, enemy, good, "medi", "ranged"); if ((good == 0) && (instance_number(obj_enunit) > 1)) { - // First target does not have vehicles, cycle through objects to find one that has vehicles var x2 = enemy.x; repeat (instance_number(obj_enunit) - 1) { if (good == 0) { x2 += 10; var enemy2 = instance_nearest(x2, y, obj_enunit); if ((enemy2.veh > 0) && (good == 0)) { - good = scr_target(enemy2, "medi"); // This target has vehicles, blow it to hell + good = scr_target(enemy2, "medi"); + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"weapon[{i}] scr_target(medi) at next column -> {enemy2.dudes[good]} in {obj_ncombat.combat_debugger.resolve_label(enemy2)}"); scr_shoot(i, enemy2, good, "medi", "ranged"); once_only = 1; } @@ -169,8 +179,8 @@ try { } if (good == 0) { ap = 0; - } // Next up is infantry - // Was previously ap=1; + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"weapon[{i}] ({wep[i]}) medi -> no monsters found, falling back to infantry"); + } } if (!instance_exists(enemy)) { engaged = false; @@ -179,22 +189,23 @@ try { } if ((ap == 0) && (once_only == 0)) { - // Check for men + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"weapon[{i}] ({wep[i]}) -> targeting infantry"); good = 0; if (enemy.men + enemy.medi > 0) { - good = scr_target(enemy, "men"); // First target has vehicles, blow it to hell + good = scr_target(enemy, "men"); + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"weapon[{i}] scr_target(men) -> {enemy.dudes[good]} in {obj_ncombat.combat_debugger.resolve_label(enemy)}"); scr_shoot(i, enemy, good, "att", "ranged"); } if ((good == 0) && (instance_number(obj_enunit) > 1)) { - // First target does not have vehicles, cycle through objects to find one that has vehicles var x2 = enemy.x; repeat (instance_number(obj_enunit) - 1) { if (good == 0) { x2 += 10; var enemy2 = instance_nearest(x2, y, obj_enunit); if ((enemy2.men > 0) && (good == 0)) { - good = scr_target(enemy2, "men"); // This target has vehicles, blow it to hell + good = scr_target(enemy2, "men"); + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"weapon[{i}] scr_target(men) at next column -> {enemy2.dudes[good]} in {obj_ncombat.combat_debugger.resolve_label(enemy2)}"); scr_shoot(i, enemy2, good, "att", "ranged"); once_only = 1; } @@ -219,11 +230,13 @@ try { } if ((apa[i] == 1) && (once_only == 0)) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"melee weapon[{i}] ({wep[i]}) AP -> targeting vehicles"); // Check for vehicles var g = 0, good = 0; if (enemy.veh > 0) { - good = scr_target(enemy, "veh"); // First target has vehicles, blow it to hell + good = scr_target(enemy, "veh"); + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"melee scr_target(veh) -> {enemy.dudes_vehicle[good]} in {obj_ncombat.combat_debugger.resolve_label(enemy)}"); if (range[i] == 1) { scr_shoot(i, enemy, good, "arp", "melee"); } @@ -233,7 +246,8 @@ try { } if ((good == 0) && (att[i] > 0)) { ap = 0; - } // Fuck it, shoot at infantry + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"melee weapon[{i}] AP -> no vehicles, fallback to infantry"); + } if (!instance_exists(enemy)) { engaged = false; continue; @@ -241,11 +255,12 @@ try { } if ((enemy.veh == 0) && (enemy.medi > 0) && (once_only == 0)) { - // Check for vehicles + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"melee weapon[{i}] ({wep[i]}) -> targeting monsters"); var g = 0, good = 0; if (enemy.medi > 0) { - good = scr_target(enemy, "medi"); // First target has vehicles, blow it to hell + good = scr_target(enemy, "medi"); + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"melee scr_target(medi) -> {enemy.dudes[good]} in {obj_ncombat.combat_debugger.resolve_label(enemy)}"); if (range[i] == 1) { scr_shoot(i, enemy, good, "medi", "melee"); } @@ -255,7 +270,8 @@ try { } if ((good == 0) && (att[i] > 0)) { ap = 0; - } // Fuck it, shoot at infantry + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"melee weapon[{i}] medi -> no monsters, fallback to infantry"); + } if (!instance_exists(enemy)) { engaged = false; continue; @@ -263,11 +279,12 @@ try { } if ((ap == 0) && (once_only == 0)) { - // Check for men + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"melee weapon[{i}] ({wep[i]}) -> targeting infantry"); var good = 0; if ((enemy.men > 0) && (once_only == 0)) { good = scr_target(enemy, "men"); + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.TARGETING, $"melee scr_target(men) -> {enemy.dudes[good]} in {obj_ncombat.combat_debugger.resolve_label(enemy)}"); if (range[i] == 1) { scr_shoot(i, enemy, good, "att", "melee"); } diff --git a/scripts/scr_clean/scr_clean.gml b/scripts/scr_clean/scr_clean.gml index e5ef92106..259f43671 100644 --- a/scripts/scr_clean/scr_clean.gml +++ b/scripts/scr_clean/scr_clean.gml @@ -7,6 +7,8 @@ function compress_enemy_array(_target_column) { return; } + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.CLEANUP, $"compress_enemy_array column={obj_ncombat.combat_debugger.resolve_label(_target_column)}"); + with (_target_column) { // Define all data arrays to be processed with their default values var _data_arrays = [ @@ -88,6 +90,7 @@ function destroy_empty_column(_target_column) { } } if ((_alive == 0) && (owner != 1)) { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.CLEANUP, $"destroy_empty_column column={obj_ncombat.combat_debugger.resolve_label(_target_column)} destroyed"); instance_destroy(); } } @@ -143,6 +146,8 @@ function scr_clean(target_object, target_is_infantry, hostile_shots, hostile_dam // hostile_splash: The splash damage modifier. Indicates if the weapon affects multiple targets or has an area-of-effect component. try { + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.SHOOTING, $"scr_clean target={obj_ncombat.combat_debugger.resolve_label(target_object)} is_infantry={target_is_infantry} shots={hostile_shots} dmg={hostile_damage} weapon={hostile_weapon} range={hostile_range} splash={hostile_splash} ap={hostile_armour_pierce}"); + with (target_object) { if (obj_ncombat.wall_destroyed == 1) { exit; @@ -220,6 +225,8 @@ function damage_infantry(_damage_data, _shots, _damage, _hostile_armour_pierce) } } + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.DAMAGE, $"damage_infantry valid_marines={array_length(valid_marines)} shots={_shots} dmg={_damage} ap={_hostile_armour_pierce}"); + // Apply damage for each shot for (var shot = 0; shot < _shots; shot++) { if (array_length(valid_marines) == 0) { @@ -279,6 +286,8 @@ function damage_infantry(_damage_data, _shots, _damage, _hostile_armour_pierce) var chunk = max(10, 62 - (marine_ac[marine_index] * 2)); _modified_damage = (webr <= chunk) ? 5000 : 0; } */ + + var _hp_before = marine.hp(); marine.add_or_sub_health(-_modified_damage); // Check if marine is dead @@ -286,9 +295,12 @@ function damage_infantry(_damage_data, _shots, _damage, _hostile_armour_pierce) // Remove dead infantry from further hits valid_marines = array_delete_value(valid_marines, marine_index); _damage_data.units_lost++; + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.DAMAGE, $"damage_infantry marine[{marine_index}] ({_damage_data.unit_type}) KILLED: luck={_shot_luck} armour={_marine_armour} raw_dmg={_damage} mod_dmg={_modified_damage} dr={damage_resistance} hp_before={_hp_before}"); } } + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.DAMAGE, $"damage_infantry done: hits={_damage_data.hits} lost={_damage_data.units_lost}"); + return; } @@ -323,6 +335,8 @@ function damage_vehicles(_damage_data, _shots, _damage, _hostile_armour_pierce) } } + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.DAMAGE, $"damage_vehicles valid_vehicles={array_length(valid_vehicles)} shots={_shots} dmg={_damage} ap={_hostile_armour_pierce}"); + // Apply damage for each hostile shot, until we run out of targets for (var shot = 0; shot < _shots; shot++) { if (array_length(valid_vehicles) == 0) { @@ -342,6 +356,7 @@ function damage_vehicles(_damage_data, _shots, _damage, _hostile_armour_pierce) if (enemy == 13 && _modified_damage < 1) { _modified_damage = 1; } + var _hp_before = veh_hp[veh_index]; veh_hp[veh_index] -= _modified_damage; _damage_data.unit_type = veh_type[veh_index]; @@ -350,6 +365,7 @@ function damage_vehicles(_damage_data, _shots, _damage, _hostile_armour_pierce) veh_dead[veh_index] = 1; _damage_data.units_lost++; obj_ncombat.player_forces -= 1; + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.DAMAGE, $"damage_vehicles veh[{veh_index}] ({_damage_data.unit_type}) DESTROYED: armour={veh_ac[veh_index] * _armour_mod} raw_dmg={_damage} mod_dmg={_modified_damage} hp_before={_hp_before}"); // Record loss var existing_index = array_get_index(lost, veh_type[veh_index]); @@ -365,5 +381,7 @@ function damage_vehicles(_damage_data, _shots, _damage, _hostile_armour_pierce) } } + obj_ncombat.combat_debugger.add(eCOMBAT_CATEGORY.DAMAGE, $"damage_vehicles done: hits={_damage_data.hits} lost={_damage_data.units_lost}"); + return; } From 18397360b640ed518103ae38fa3afa6a9ad01225 Mon Sep 17 00:00:00 2001 From: EttyKitty <20323032+EttyKitty@users.noreply.github.com> Date: Sat, 11 Jul 2026 01:22:25 +0300 Subject: [PATCH 08/14] fix: obj_bomb_select string_delete warning --- objects/obj_bomb_select/Draw_0.gml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/objects/obj_bomb_select/Draw_0.gml b/objects/obj_bomb_select/Draw_0.gml index 60faedc28..488c53e19 100644 --- a/objects/obj_bomb_select/Draw_0.gml +++ b/objects/obj_bomb_select/Draw_0.gml @@ -174,14 +174,13 @@ if ((max_ships > 0) && instance_exists(obj_star_select)) { // Check if ship_index is still within range if (ship_index < array_length(ship) && ship[ship_index] != "") { - // Delete the string from the 20th character onwards - var num = string_delete(ship[ship_index], 20, 999); + var ship_name = ship[ship_index]; // Calculate button position based on row and column var buttonX = bomb_window.x1 + 24 + col * buttonSpacingX; var buttonY = bomb_window.y1 + 172 + row * buttonSpacingY; // Draw the unit buttons and handle selection - if (point_and_click(draw_unit_buttons([buttonX, buttonY, buttonX + 105, buttonY + 20], string_truncate(num, 200), [1, 1], ship_all[ship_index] ? #34bc75 : #bf4040, fa_center, fnt_40k_10, ship_all[ship_index] ? 1 : 0.5))) { + if (point_and_click(draw_unit_buttons([buttonX, buttonY, buttonX + 105, buttonY + 20], string_truncate(ship_name, 200), [1, 1], ship_all[ship_index] ? #34bc75 : #bf4040, fa_center, fnt_40k_10, ship_all[ship_index] ? 1 : 0.5))) { ship_all[ship_index] = !ship_all[ship_index]; ships_selected += ship_all[ship_index] ? 1 : -1; From deba17bd2acf023a87b59fa71f7b625373de70ee Mon Sep 17 00:00:00 2001 From: EttyKitty <20323032+EttyKitty@users.noreply.github.com> Date: Sat, 11 Jul 2026 01:38:04 +0300 Subject: [PATCH 09/14] fix: Marine location planet num truncation --- .../scr_draw_management_unit.gml | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/scripts/scr_draw_management_unit/scr_draw_management_unit.gml b/scripts/scr_draw_management_unit/scr_draw_management_unit.gml index e945d6627..4e8b50c7e 100644 --- a/scripts/scr_draw_management_unit/scr_draw_management_unit.gml +++ b/scripts/scr_draw_management_unit/scr_draw_management_unit.gml @@ -1,6 +1,7 @@ /// @self Asset.GMObject.obj_controller function scr_draw_management_unit(selected, yy = 0, xx = 0, draw = true, click_lock = false) { var assignment = "none"; + /// @type {Struct.TTRPG_stats|Array} var _unit = noone; var string_role = ""; var health_string = ""; @@ -8,7 +9,8 @@ function scr_draw_management_unit(selected, yy = 0, xx = 0, draw = true, click_l var jailed = false; var impossible = !is_struct(display_unit[selected]) && !is_array(display_unit[selected]); var is_man = false; - var unit_location_string = ""; + var _loc_name = ""; + var _loc_planet_num = ""; var unit_specialist = false; if (man[selected] == "man" && is_struct(display_unit[selected])) { is_man = true; @@ -37,32 +39,29 @@ function scr_draw_management_unit(selected, yy = 0, xx = 0, draw = true, click_l unit_specialist = is_specialist(_unit.role()); if (_unit.in_jail()) { jailed = true; - unit_location_string = "=Penitorium="; + _loc_name = "=Penitorium="; } else { var unit_location = _unit.marine_location(); string_role = _unit.name_role(); unit_specialism_option = false; //TODO make static to handle - unit_location_string = string(ma_loc[selected]); + _loc_name = string(ma_loc[selected]); if (_unit.controllable()) { if (unit_location[0] == eLOCATION_TYPES.PLANET) { - unit_location_string = unit_location[2]; - //get roman numeral for system planet - unit_location_string += scr_roman(unit_location[1]); + _loc_name = unit_location[2]; + _loc_planet_num = scr_roman(unit_location[1]); } else if (unit_location[0] == eLOCATION_TYPES.SHIP) { - unit_location_string = obj_ini.ship[unit_location[1]]; + _loc_name = obj_ini.ship[unit_location[1]]; } - } else { - unit_location_string = ma_loc[selected]; } assignment = _unit.assignment(); if (assignment != "none") { - unit_location_string += $"({assignment})"; + _loc_name += $"({assignment})"; } else if ((fest_planet == 0) && (fest_sid > -1) && (fest_repeats > 0) && (ma_lid[selected] == fest_sid)) { - unit_location_string = "=Event="; + _loc_name = "=Event="; eventing = true; } else if ((fest_planet == 1) && (fest_wid > 0) && (fest_repeats > 0) && (ma_wid[selected] == fest_wid) && (ma_loc[selected] == fest_star)) { - unit_location_string = "=Event="; + _loc_name = "=Event="; eventing = true; } } @@ -105,13 +104,12 @@ function scr_draw_management_unit(selected, yy = 0, xx = 0, draw = true, click_l } } else if (man[selected] == "vehicle" && is_array(display_unit[selected]) && draw) { string_role = string(ma_role[selected]); - unit_location_string = string(ma_loc[selected]); + _loc_name = string(ma_loc[selected]); if (ma_wid[selected] != 0) { - //numeral for vehicle planet - unit_location_string += scr_roman(ma_wid[selected]); + _loc_planet_num = scr_roman(ma_wid[selected]); } else if (ma_lid[selected] > -1) { - unit_location_string = obj_ini.ship[ma_lid[selected]]; + _loc_name = obj_ini.ship[ma_lid[selected]]; } health_string = string(round(ma_health[selected])) + "% HP"; // Need abbreviations here @@ -344,10 +342,18 @@ function scr_draw_management_unit(selected, yy = 0, xx = 0, draw = true, click_l draw_text_transformed(xx + 27.5 + 8, yy + 66.5, string_hash_to_newline(string(string_role)), name_xr, 1, 0); // Draw current location - if (location_out_of_player_control(unit_location_string) || (unit_location_string == "=Penitorium=") || (assignment != "none")) { + if (location_out_of_player_control(_loc_name) || (_loc_name == "=Penitorium=") || (assignment != "none")) { draw_set_alpha(0.5); } - var truncatedLocation = string_truncate(string(unit_location_string), 130); // Truncate the location string to 100 pixels + + var truncatedLocation = ""; + if (_loc_planet_num != "") { + var _avail = max(130 - string_width(_loc_planet_num), 0); + truncatedLocation = $"{string_truncate(_loc_name, _avail)} {_loc_planet_num}"; + } else { + truncatedLocation = string_truncate(string(_loc_name), 130); + } + draw_text(xx + 430 + 8, yy + 66, truncatedLocation); // LOC draw_set_alpha(1); From f7e8b5983956845db60dedebe8a527a580779843 Mon Sep 17 00:00:00 2001 From: EttyKitty <20323032+EttyKitty@users.noreply.github.com> Date: Sat, 11 Jul 2026 01:57:23 +0300 Subject: [PATCH 10/14] refactor: eFACTION explicit members, COUNT --- scripts/macros/macros.gml | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/scripts/macros/macros.gml b/scripts/macros/macros.gml index f293b5c66..04c500b4a 100644 --- a/scripts/macros/macros.gml +++ b/scripts/macros/macros.gml @@ -35,18 +35,19 @@ global.alliance_grades = ["Hated", "Hostile","Suspicious","Uneasy","Neutral","Al enum eFACTION { PLAYER = 1, - IMPERIUM, - MECHANICUS, - INQUISITION, - ECCLESIARCHY, - ELDAR, - ORK, - TAU, - TYRANIDS, - CHAOS, - HERETICS, - GENESTEALER, - NECRONS = 13 + IMPERIUM = 2, + MECHANICUS = 3, + INQUISITION = 4, + ECCLESIARCHY = 5, + ELDAR = 6, + ORK = 7, + TAU = 8, + TYRANIDS = 9, + CHAOS = 10, + HERETICS = 11, + GENESTEALER = 12, + NECRONS = 13, + _COUNT } From 29b27743eec995bb57046fe2d163a8cd33c63fd3 Mon Sep 17 00:00:00 2001 From: EttyKitty <20323032+EttyKitty@users.noreply.github.com> Date: Sat, 11 Jul 2026 01:58:23 +0300 Subject: [PATCH 11/14] refactor: Add enums to star_ownership --- scripts/scr_star_ownership/scr_star_ownership.gml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/scr_star_ownership/scr_star_ownership.gml b/scripts/scr_star_ownership/scr_star_ownership.gml index cf8dc3f30..7efbe9f21 100644 --- a/scripts/scr_star_ownership/scr_star_ownership.gml +++ b/scripts/scr_star_ownership/scr_star_ownership.gml @@ -27,13 +27,13 @@ function scr_star_ownership(argument0) { } } var _set_to_first = false; - if (p_owner[run] == 7 && p_orks[run] <= 0) { + if (p_owner[run] == eFACTION.ORK && p_orks[run] <= 0) { _set_to_first = true; } if (_set_to_first) { var _first = p_first[run]; if (p_first[run] == eFACTION.ORK) { - p_owner[run] = 2; + p_owner[run] = eFACTION.IMPERIUM; } else { p_owner[run] = p_first[run]; } @@ -45,15 +45,15 @@ function scr_star_ownership(argument0) { p_owner[run] = eFACTION.IMPERIUM; p_influence[run][eFACTION.TAU] = round(p_influence[run][eFACTION.TAU] / 2); } - if (p_owner[run] == 10 && p_chaos[run] == 0 && p_traitors[run] == 0 && p_population[run] <= 0) { + if (p_owner[run] == eFACTION.CHAOS && p_chaos[run] == 0 && p_traitors[run] == 0 && p_population[run] <= 0) { p_owner[run] = p_first[run]; p_heresy[run] = 0; if (p_owner[run] == 10) { - p_owner[run] = 2; + p_owner[run] = eFACTION.IMPERIUM; } } if (p_type[run] == "Daemon") { - p_owner[run] = 10; + p_owner[run] = eFACTION.CHAOS; } var _nid_chosen = false; @@ -133,7 +133,7 @@ function scr_star_ownership(argument0) { p_type[run] = "Daemon"; p_fortified[run] = 6; p_traitors[run] = 7; - p_owner[run] = 10; + p_owner[run] = eFACTION.CHAOS; delete_features(p_feature[run], eP_FEATURES.DAEMONIC_INCURSION); } } From 799f73cb089d65a315de66ae1b46f9f06d756665 Mon Sep 17 00:00:00 2001 From: EttyKitty <20323032+EttyKitty@users.noreply.github.com> Date: Sat, 11 Jul 2026 02:21:27 +0300 Subject: [PATCH 12/14] fix: Tyranid planet ownership; Cleansed alert --- scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml | 10 ++++-- .../scr_star_ownership/scr_star_ownership.gml | 34 +++++++++++-------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml b/scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml index 2ed459f9e..ff728de2b 100644 --- a/scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml +++ b/scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml @@ -46,7 +46,7 @@ function scr_enemy_ai_a() { var total_garrison = 0; var _planet_data; for (var _run = 1; _run <= planets; _run++) { - + /// @type {Struct.PlanetData} _planet_data = system_datas[_run]; _garrison = _planet_data.garrisons; _sabatours = _planet_data.sabatours; @@ -1204,7 +1204,7 @@ function scr_enemy_ai_a() { // 135; - var planet_saved = (p_player[_run] + p_raided[_run]) > 0 && p_orks[_run] == 0 && p_tyranids[_run] < 4 && p_chaos[_run] == 0 && p_traitors[_run] == 0 && p_necrons[_run] == 0 && p_tau[_run] == 0; + var planet_saved = (p_player[_run] + p_raided[_run] > 0) && (p_orks[_run] + p_tyranids[_run] + p_chaos[_run] + p_traitors[_run] + p_necrons[_run] + p_tau[_run] <= 0); if (planet_saved) { var who_cleansed = ""; @@ -1217,18 +1217,22 @@ function scr_enemy_ai_a() { } else if (p_owner[_run] == 8 && p_pdf[_run] == 0) { who_cleansed = "Tau"; make_alert = true; + } else if (p_owner[_run] == 9) { + who_cleansed = "Tyranids"; + make_alert = true; } else if (p_owner[_run] == 13) { who_cleansed = "Necrons"; make_alert = true; } else if (p_owner[_run] == 10) { who_cleansed = "Chaos"; make_alert = true; - } else if (planet_feature_bool(p_feature[_run], eP_FEATURES.GENE_STEALER_CULT) && p_tyranids[_run] <= 0) { + } else if (planet_feature_bool(p_feature[_run], eP_FEATURES.GENE_STEALER_CULT)) { who_cleansed = "Gene Stealer Cult"; make_alert = true; delete_features(p_feature[_run], eP_FEATURES.GENE_STEALER_CULT); adjust_influence(eFACTION.TYRANIDS, -25, _run, self); } + if (make_alert) { if (p_first[_run] == 1) { p_owner[_run] = eFACTION.PLAYER; diff --git a/scripts/scr_star_ownership/scr_star_ownership.gml b/scripts/scr_star_ownership/scr_star_ownership.gml index 7efbe9f21..a8485866b 100644 --- a/scripts/scr_star_ownership/scr_star_ownership.gml +++ b/scripts/scr_star_ownership/scr_star_ownership.gml @@ -26,32 +26,38 @@ function scr_star_ownership(argument0) { p_owner[run] = eFACTION.IMPERIUM; } } - var _set_to_first = false; + if (p_owner[run] == eFACTION.ORK && p_orks[run] <= 0) { - _set_to_first = true; + p_owner[run] = p_first[run]; + if (p_owner[run] == eFACTION.ORK) { + p_owner[run] = eFACTION.IMPERIUM; + } + } + + if (p_owner[run] == eFACTION.TYRANIDS && p_tyranids[run] <= 0) { + p_owner[run] = p_first[run]; + if (p_owner[run] == eFACTION.TYRANIDS) { + p_owner[run] = eFACTION.IMPERIUM; + } } - if (_set_to_first) { - var _first = p_first[run]; - if (p_first[run] == eFACTION.ORK) { + + if (p_owner[run] == eFACTION.CHAOS && p_chaos[run] == 0 && p_traitors[run] == 0 && p_population[run] <= 0) { + p_owner[run] = p_first[run]; + p_heresy[run] = 0; + if (p_owner[run] == eFACTION.CHAOS) { p_owner[run] = eFACTION.IMPERIUM; - } else { - p_owner[run] = p_first[run]; } } + if (p_type[run] == "Dead" && p_owner[run] != eFACTION.IMPERIUM && p_first[run] != eFACTION.PLAYER && p_first[run] != eFACTION.ECCLESIARCHY) { p_owner[run] = eFACTION.IMPERIUM; } + if (p_owner[run] == eFACTION.TAU && p_tau[run] == 0 && p_pdf[run] == 0) { p_owner[run] = eFACTION.IMPERIUM; p_influence[run][eFACTION.TAU] = round(p_influence[run][eFACTION.TAU] / 2); } - if (p_owner[run] == eFACTION.CHAOS && p_chaos[run] == 0 && p_traitors[run] == 0 && p_population[run] <= 0) { - p_owner[run] = p_first[run]; - p_heresy[run] = 0; - if (p_owner[run] == 10) { - p_owner[run] = eFACTION.IMPERIUM; - } - } + if (p_type[run] == "Daemon") { p_owner[run] = eFACTION.CHAOS; } From a1b90bb265159a22904a7c33ae7358ad7911f2fe Mon Sep 17 00:00:00 2001 From: EttyKitty <20323032+EttyKitty@users.noreply.github.com> Date: Sat, 11 Jul 2026 02:28:46 +0300 Subject: [PATCH 13/14] refactor: eFACTION in enemy_ai_a --- scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml | 38 +++++++++++------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml b/scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml index ff728de2b..fbe98c18f 100644 --- a/scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml +++ b/scripts/scr_enemy_ai_a/scr_enemy_ai_a.gml @@ -71,7 +71,7 @@ function scr_enemy_ai_a() { continue; } else if ((planet_forces[eFACTION.PLAYER] <= 0) && (planet_forces[eFACTION.ORK] > 0)) { //orks prevail over other factions - if (p_owner[_run] == 2 || p_owner[_run] == 6) { + if (p_owner[_run] == eFACTION.IMPERIUM || p_owner[_run] == eFACTION.ELDAR) { p_owner[_run] = eFACTION.ORK; } } @@ -96,7 +96,7 @@ function scr_enemy_ai_a() { var sisters_score = p_sisters[_run]; // if (p_eldar[_run]>0) then eldar_score=p_eldar[_run]+1; - if ((p_tyranids[_run] > 0) && (stop != 1) && (p_owner[_run] != 9)) { + if ((p_tyranids[_run] > 0) && (stop != 1) && (p_owner[_run] != eFACTION.TYRANIDS)) { // This might have been causing the problem /*if (p_tyranids[_run]<5) and (p_guardsmen[_run]>0){ if (p_tyranids[_run]=4) then p_guardsmen[_run]=max(0,p_guardsmen[_run]-100000); @@ -145,7 +145,7 @@ function scr_enemy_ai_a() { if ((p_sisters[_run] > 0) && (stop != 1)) { // THEY MARCH FOR THE ECCLESIARCHY - if ((p_player[_run] > 0) && (obj_controller.faction_status[5] == "War")) { + if ((p_player[_run] > 0) && (obj_controller.faction_status[eFACTION.ECCLESIARCHY] == "War")) { sisters_attack = "player"; } else { if (p_tau[_run] > 0) { @@ -157,10 +157,10 @@ function scr_enemy_ai_a() { if (p_necrons[_run] > 0) { sisters_attack = "necrons"; } - if ((p_pdf[_run] > 0) && (p_owner[_run] == 8)) { + if ((p_pdf[_run] > 0) && (p_owner[_run] == eFACTION.TAU)) { sisters_attack = "pdf"; } - if ((p_pdf[_run] > 0) && (p_owner[_run] == 1) && (obj_controller.faction_status[5] == "War")) { + if ((p_pdf[_run] > 0) && (p_owner[_run] == eFACTION.PLAYER) && (obj_controller.faction_status[eFACTION.ECCLESIARCHY] == "War")) { sisters_attack = "pdf"; } if (p_traitors[_run] > 0) { @@ -169,7 +169,7 @@ function scr_enemy_ai_a() { if (p_chaos[_run] > 0) { sisters_attack = "chaos"; } - if ((p_player[_run] > 0) && (obj_controller.faction_status[5] == "War")) { + if ((p_player[_run] > 0) && (obj_controller.faction_status[eFACTION.ECCLESIARCHY] == "War")) { sisters_attack = "player"; } // Always goes after traitors first @@ -243,7 +243,7 @@ function scr_enemy_ai_a() { } } - if ((p_tau[_run] > 0) && (stop != 1) && (p_owner[_run] != 8)) { + if ((p_tau[_run] > 0) && (stop != 1) && (p_owner[_run] != eFACTION.TAU)) { // They don't own the planet, go ham // if (eldar_score>0) then tau_attack="eldar"; if (guard_score > 0) { @@ -276,11 +276,11 @@ function scr_enemy_ai_a() { if ((tau_attack == "") && (p_sisters[_run] > 0)) { tau_attack = "sisters"; } - if ((tau_attack == "") && (obj_controller.faction_status[8] == "War") && (p_player[_run] > 0)) { + if ((tau_attack == "") && (obj_controller.faction_status[eFACTION.TAU] == "War") && (p_player[_run] > 0)) { tau_attack = "player"; } } - if ((p_tau[_run] > 0) && (stop != 1) && (p_owner[_run] == 8)) { + if ((p_tau[_run] > 0) && (stop != 1) && (p_owner[_run] == eFACTION.TAU)) { // They own the planet // if (eldar_score>0) then tau_attack="eldar"; if (traitors_score > 0) { @@ -304,7 +304,7 @@ function scr_enemy_ai_a() { if ((tau_attack == "") && (p_sisters[_run] > 0)) { tau_attack = "sisters"; } - if ((tau_attack == "") && (obj_controller.faction_status[8] == "War") && (p_player[_run] > 0)) { + if ((tau_attack == "") && (obj_controller.faction_status[eFACTION.TAU] == "War") && (p_player[_run] > 0)) { tau_attack = "player"; } } @@ -496,7 +496,7 @@ function scr_enemy_ai_a() { } if ((p_pdf[_run] == 0) && pdf_with_player) { if ((!_planet_data.has_feature(eP_FEATURES.MONASTERY)) && (p_player[_run] <= 0)) { - p_owner[_run] = 2; + p_owner[_run] = eFACTION.IMPERIUM; dispo[_run] = -50; } } @@ -1211,19 +1211,19 @@ function scr_enemy_ai_a() { var who_return = ""; var make_alert = false; var planet_string = $"{name} {scr_roman(_run)}"; - if (p_owner[_run] == 7) { + if (p_owner[_run] == eFACTION.ORK) { who_cleansed = "Orks"; make_alert = true; - } else if (p_owner[_run] == 8 && p_pdf[_run] == 0) { + } else if (p_owner[_run] == eFACTION.TAU && p_pdf[_run] == 0) { who_cleansed = "Tau"; make_alert = true; - } else if (p_owner[_run] == 9) { + } else if (p_owner[_run] == eFACTION.TYRANIDS) { who_cleansed = "Tyranids"; make_alert = true; - } else if (p_owner[_run] == 13) { + } else if (p_owner[_run] == eFACTION.NECRONS) { who_cleansed = "Necrons"; make_alert = true; - } else if (p_owner[_run] == 10) { + } else if (p_owner[_run] == eFACTION.CHAOS) { who_cleansed = "Chaos"; make_alert = true; } else if (planet_feature_bool(p_feature[_run], eP_FEATURES.GENE_STEALER_CULT)) { @@ -1252,7 +1252,7 @@ function scr_enemy_ai_a() { scr_event_log("", $"{who_cleansed} cleansed from {planet_string}", name); scr_alert("green", "owner", $"{who_cleansed} cleansed from {planet_string}. Control returned to {who_return}", x, y); if (dispo[_run] >= 101) { - p_owner[_run] = 1; + p_owner[_run] = eFACTION.PLAYER; } } } @@ -1275,7 +1275,7 @@ function scr_enemy_ai_a() { i += 1; if (p_type[i] == "Daemon") { p_heresy[i] = 200; - p_owner[i] = 10; + p_owner[i] = eFACTION.CHAOS; } if ((p_population[i] <= 0) && (p_large[i] == 0) && (p_chaos[i] == 0) && (p_traitors[i] == 0) && (p_tau[i] == 0) && (p_type[i] != "Daemon")) { @@ -1286,7 +1286,7 @@ function scr_enemy_ai_a() { p_large[i] = 0; } - if ((p_owner[i] == 2) && (p_type[i] != "Dead") && (planets >= i) && (p_tyranids[i] == 0) && (p_chaos[i] == 0) && (p_traitors[i] == 0) && (p_eldar[i] == 0) && (p_tau[i] == 0)) { + if ((p_owner[i] == eFACTION.IMPERIUM) && (p_type[i] != "Dead") && (planets >= i) && (p_tyranids[i] == 0) && (p_chaos[i] == 0) && (p_traitors[i] == 0) && (p_eldar[i] == 0) && (p_tau[i] == 0)) { var military, pdf, rando, contin; military = 0; pdf = 0; From a992c24d733e7edf87753fa26de14d24916f4cb9 Mon Sep 17 00:00:00 2001 From: EttyKitty <20323032+EttyKitty@users.noreply.github.com> Date: Sat, 11 Jul 2026 02:43:51 +0300 Subject: [PATCH 14/14] fix: Ecclesiarchy in xenos_and_heretics (based) --- scripts/scr_PlanetData/scr_PlanetData.gml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scr_PlanetData/scr_PlanetData.gml b/scripts/scr_PlanetData/scr_PlanetData.gml index 1e4ce27b8..b30b02776 100644 --- a/scripts/scr_PlanetData/scr_PlanetData.gml +++ b/scripts/scr_PlanetData/scr_PlanetData.gml @@ -798,7 +798,7 @@ function PlanetData(_planet, _system) constructor { static xenos_and_heretics = function() { var xh_force = 0; - for (var i = 5; i < array_length(planet_forces); i++) { + for (var i = 6; i < array_length(planet_forces); i++) { xh_force += planet_forces[i]; } return xh_force;