Skip to content

feat: Lightning Warriors and a boatload of stuff#1283

Open
CptMacTavish2224 wants to merge 50 commits into
Adeptus-Dominus:mainfrom
CptMacTavish2224:LWB_1.1
Open

feat: Lightning Warriors and a boatload of stuff#1283
CptMacTavish2224 wants to merge 50 commits into
Adeptus-Dominus:mainfrom
CptMacTavish2224:LWB_1.1

Conversation

@CptMacTavish2224

@CptMacTavish2224 CptMacTavish2224 commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator
  • COMBAT TEXT REWORK:
    • Combat log now accurately represents:
      • kills: green
      • hits but not kills [injuries]: bright green
      • non-pens: white
    • Psychic force uses are collapsed into a list of "X Avenge is cast" for less log spam
    • inaccurate same target spam removed
    • multi-unit kills of a single origin are listed as a single entry
    • characters all get their own line
    • various typos fixed
    • weapons not fired will be listed in a "X held fire" message in blue
    • scrollable now biaaaaaaatch
  • COMBAT REVAMP:
    • old damage spill deleted
    • all units now when firing shoot when damage left:
      • primary target
      • next unit in formation block
      • next formation block
  • Bikes Rebalance:
    • Attack Bikes now use ranged damage instead of melee in speed force calcs
  • probably more that I forgot about I should stop coding at 3 AM

General LW_Beta Notes

  • Squads of Bikers and Attack Bikers:
    • Roles added to defaults
    • Promotion available by default
    • Fully customisable role settings
    • Unique formation block
    • Speed Force simulates a driveby
  • Attack Bikers:
    • One marine simulates the two-person team by buffs in unique Attack Bike item
    • additional ranged hands allow using heavier weapons
  • Gamestart text blurb now accurately represents default roles in the list
    more detailed info in the first Lightning Warriors Beta release

Testing

Checked everything I could, it seems this is on par with main in bugs


Summary by cubic

Adds the Lightning Warriors beta with bike-heavy squads and the “Speed Force” drive-by. Reworks the combat log with color, summaries, scrollback (wheel/drag), and stability fixes for long turns; cleans up company templates and shooting flow for clearer battles.

  • New Features

    • Lightning Warriors chapter: bike_squad/attack_bike_squad focus, promotions, unique bike formation and icon.
    • Bikes overhaul: stat/tag updates, Speed Force added; Attack Bikes use ranged-based Speed Force.
    • Combat log: color-coded kills/injuries/non-pens, collapsed psychic casts, “held fire” lines, mouse-wheel/drag scrollback with larger capacity.
    • Combat flow: legacy spillover removed; fire advances primary → next in block → next block; multi-target kills summarized.
  • Refactors and Fixes

    • Company/squad gen via default_squads; generator supports multi-role sources and unique-role checks; equal Scouts/Specialists templates fixed; company view sorted and stable.
    • Biker roles wired across creation, promotion, settings, formation bars; dedicated bike column and drag support.
    • Enemy column cleanup during player fire to prevent shooting empty formations and ensure accurate “held fire” reporting; long-turn anti-stall safeguards.
    • Data/text fixes: Flesh Tearers id, “monastery” spelling, Librarian role label, Contemptor description; chapter template refreshed.

Written for commit f6c5244. Summary will update on new commits.

Review in cubic

@github-actions github-actions Bot added Area: JSON Changes to external JSON files or their under-the-hood functionality Area: Sprites Changes to sprites/images or their under-the-hood functionality Size: Warning Type: Feature Adds something new labels Jun 30, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

24 issues found across 47 files

Confidence score: 2/5

  • The riskiest issue is data integrity in datafiles/main/squads/base_squads.json, datafiles/main/chapters/template.JSON, and datafiles/main/chapters/34.json: invalid JSON comments, malformed key names, and duplicate keys can break parsing or silently load wrong values at startup/content load — fix these files and run a full JSON/schema validation pass before merging.
  • datafiles/main/squads/equal_spescout.json appears to regress 10th company composition from a unique scout+tactical setup to effectively command+single devastator, which can materially alter roster generation and campaign balance for users — restore intended company-10 squads and verify generated company totals in-game before merge.
  • In scripts/scr_UnitGroup/scr_UnitGroup.gml, sergeant selection/promotion can happen before slot viability checks, so wrong-role marines may be promoted and state can drift even when squad creation fails — reorder the flow to validate squad/slot first, then mutate role/traits, and add a targeted regression test for failed creation paths.
  • There are multiple runtime edge-case risks in objects/obj_ncombat/Alarm_3.gml, scripts/scr_initialize_custom/scr_initialize_custom.gml, and scripts/scr_shoot/scr_shoot.gml (combat log drain stall, scout bank overdraft/override check mismatch, and zero-HP division path), which together increase odds of hard-to-reproduce gameplay bugs — add guards for bounds/zero-HP, align instance-variable checks, and smoke-test long combats plus custom initialization before merging.

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread datafiles/main/squads/base_squads.json
Comment thread datafiles/main/chapters/34.json
Comment thread datafiles/main/chapters/template.JSON Outdated
Comment thread datafiles/main/squads/equal_spescout.json Outdated
Comment thread scripts/scr_UnitGroup/scr_UnitGroup.gml Outdated
Comment thread objects/obj_popup/Create_0.gml Outdated
Comment thread scripts/scr_powers/scr_powers.gml Outdated
Comment thread objects/obj_ncombat/Draw_0.gml
Comment thread objects/obj_pnunit/Alarm_0.gml Outdated
Comment thread objects/obj_pnunit/Alarm_0.gml Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 18 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread scripts/scr_squads/scr_squads.gml Outdated
Comment thread scripts/scr_UnitGroup/scr_UnitGroup.gml
cubic-dev-ai[bot]
cubic-dev-ai Bot previously approved these changes Jun 30, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 2 files (changes from recent commits).

Re-trigger cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7 issues found across 47 files

Confidence score: 2/5

  • scripts/scr_squads/scr_squads.gml detects invalid squad types but still dereferences the bad key, which can hard-crash squad setup flows for players. Return early (or otherwise stop execution) as soon as a squad type is invalid before merging.
  • scripts/scr_shoot/scr_shoot.gml can enter spill damage on ranks with nonpositive HP, creating divide-by-zero/negative-HP behavior and targeting ranks normal alive-rank logic would skip; it also spends Speed Force ammo before confirming there are valid targets. Skip zombie ranks before spill math and move ammo consumption after _total > 0 is confirmed.
  • Formation/state consistency is at risk across objects/obj_pnunit/Alarm_0.gml, scripts/scr_company_order/scr_company_order.gml, and objects/obj_controller/Create_0.gml: the 30-rank empty-column scan can delete still-live formations, company 0 can be reorganized by 1-based defaults, and bike placements can stay stale after reset. Reuse destroy_empty_column, guard company 0 in default squad application, and include bat_bike_for in reset paths to keep combat layouts stable.
  • scripts/scr_squads/scr_squads.gml stores company override entries by reference, so editing a live arrangement can mutate the override template and cause hard-to-reproduce future layout drift. Store/copy overrides by value to isolate templates from runtime edits before merge.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="objects/obj_controller/Create_0.gml">

<violation number="1" location="objects/obj_controller/Create_0.gml:830">
P2: Add bat_bike_for to the formation reset path. Otherwise resetting/customizing battle formations leaves bikes using stale placement while every other unit type returns to defaults.</violation>
</file>

<file name="objects/obj_pnunit/Alarm_0.gml">

<violation number="1" location="objects/obj_pnunit/Alarm_0.gml:291">
P2: Do not duplicate the empty-column scan with a 30-rank limit; it can destroy formations that still have live ranks beyond slot 30. Reuse `destroy_empty_column` so cleanup matches the rest of combat.</violation>
</file>

<file name="scripts/scr_shoot/scr_shoot.gml">

<violation number="1" location="scripts/scr_shoot/scr_shoot.gml:286">
P2: Also skip zombie ranks with nonpositive HP before entering the spill loop. Otherwise the new damage calculation can divide by zero/negative HP or keep firing at a rank that `find_next_alive_rank` would never consider alive.</violation>

<violation number="2" location="scripts/scr_shoot/scr_shoot.gml:473">
P2: Move Speed Force ammo consumption until after confirming `_total > 0`. Current ordering can consume ammo on an empty battlefield.</violation>
</file>

<file name="scripts/scr_company_order/scr_company_order.gml">

<violation number="1" location="scripts/scr_company_order/scr_company_order.gml:73">
P2: Guard company 0 before applying default_squads; otherwise the chapter/HQ company can be reorganized into normal bike/tactical templates even though arrangements are 1-based.</violation>
</file>

<file name="scripts/scr_squads/scr_squads.gml">

<violation number="1" location="scripts/scr_squads/scr_squads.gml:381">
P2: Invalid squad types are detected but not stopped; function still dereferences the invalid key and can crash.</violation>

<violation number="2" location="scripts/scr_squads/scr_squads.gml:925">
P2: Company override entries are stored by reference, so editing live arrangement can mutate override templates unexpectedly.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

bat_formation_type = array_create(_count, 0);
bat_deva_for = array_create(_count, 1);
bat_assa_for = array_create(_count, 4);
bat_bike_for = array_create(_count, 4);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Add bat_bike_for to the formation reset path. Otherwise resetting/customizing battle formations leaves bikes using stale placement while every other unit type returns to defaults.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At objects/obj_controller/Create_0.gml, line 830:

<comment>Add bat_bike_for to the formation reset path. Otherwise resetting/customizing battle formations leaves bikes using stale placement while every other unit type returns to defaults.</comment>

<file context>
@@ -827,6 +827,7 @@ bat_formation = array_create(_count, "");
 bat_formation_type = array_create(_count, 0);
 bat_deva_for = array_create(_count, 1);
 bat_assa_for = array_create(_count, 4);
+bat_bike_for = array_create(_count, 4);
 bat_tact_for = array_create(_count, 2);
 bat_vete_for = array_create(_count, 2);
</file context>

Comment on lines +291 to +301
with (obj_enunit) {
var _alive = 0;
for (var _rr = 1; _rr <= 30; _rr++) {
if (dudes_num[_rr] > 0 && dudes_hp[_rr] > 0) {
_alive += dudes_num[_rr];
}
}
if ((_alive == 0) && (owner != 1)) {
instance_destroy();
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Do not duplicate the empty-column scan with a 30-rank limit; it can destroy formations that still have live ranks beyond slot 30. Reuse destroy_empty_column so cleanup matches the rest of combat.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At objects/obj_pnunit/Alarm_0.gml, line 291:

<comment>Do not duplicate the empty-column scan with a 30-rank limit; it can destroy formations that still have live ranks beyond slot 30. Reuse `destroy_empty_column` so cleanup matches the rest of combat.</comment>

<file context>
@@ -244,17 +268,49 @@ try {
 
+    // Safety net: drop empty/zombie formations the firing loop never reached, so a lingering corpse
+    // can't keep the battle alive.
+    with (obj_enunit) {
+        var _alive = 0;
+        for (var _rr = 1; _rr <= 30; _rr++) {
</file context>
Suggested change
with (obj_enunit) {
var _alive = 0;
for (var _rr = 1; _rr <= 30; _rr++) {
if (dudes_num[_rr] > 0 && dudes_hp[_rr] > 0) {
_alive += dudes_num[_rr];
}
}
if ((_alive == 0) && (owner != 1)) {
instance_destroy();
}
}
with (obj_enunit) {
destroy_empty_column(id);
}

var _dpw = att[weapon_index_position] / _shots; // per-bike damage
var _mod = max(1, splash[weapon_index_position]);
if (ammo[weapon_index_position] > 0) {
ammo[weapon_index_position] -= 1;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Move Speed Force ammo consumption until after confirming _total > 0. Current ordering can consume ammo on an empty battlefield.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/scr_shoot/scr_shoot.gml, line 473:

<comment>Move Speed Force ammo consumption until after confirming `_total > 0`. Current ordering can consume ammo on an empty battlefield.</comment>

<file context>
@@ -254,258 +246,327 @@ function scr_shoot(weapon_index_position, target_object, target_type, damage_dat
+        var _dpw = att[weapon_index_position] / _shots; // per-bike damage
+        var _mod = max(1, splash[weapon_index_position]);
+        if (ammo[weapon_index_position] > 0) {
+            ammo[weapon_index_position] -= 1;
+        }
 
</file context>

if (!instance_exists(target_object)) {
exit;
}
if (target_object.dudes_num[target_type] <= 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Also skip zombie ranks with nonpositive HP before entering the spill loop. Otherwise the new damage calculation can divide by zero/negative HP or keep firing at a rank that find_next_alive_rank would never consider alive.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/scr_shoot/scr_shoot.gml, line 286:

<comment>Also skip zombie ranks with nonpositive HP before entering the spill loop. Otherwise the new damage calculation can divide by zero/negative HP or keep firing at a rank that `find_next_alive_rank` would never consider alive.</comment>

<file context>
@@ -254,258 +246,327 @@ function scr_shoot(weapon_index_position, target_object, target_type, damage_dat
+                    if (!instance_exists(target_object)) {
+                        exit;
+                    }
+                    if (target_object.dudes_num[target_type] <= 0) {
+                        var _alive_rank = find_next_alive_rank(target_object, -1);
+                        if (_alive_rank == -1) {
</file context>
Suggested change
if (target_object.dudes_num[target_type] <= 0) {
if (target_object.dudes_num[target_type] <= 0 || target_object.dudes_hp[target_type] <= 0) {

}
}
if (_data_match) {
var _data = resolve_company_arrangement(obj_ini.chapter_squad_arrangement, co);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Guard company 0 before applying default_squads; otherwise the chapter/HQ company can be reorganized into normal bike/tactical templates even though arrangements are 1-based.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/scr_company_order/scr_company_order.gml, line 73:

<comment>Guard company 0 before applying default_squads; otherwise the chapter/HQ company can be reorganized into normal bike/tactical templates even though arrangements are 1-based.</comment>

<file context>
@@ -70,18 +70,8 @@ function scr_company_order(company) {
-                }
-            }
-            if (_data_match) {
+            var _data = resolve_company_arrangement(obj_ini.chapter_squad_arrangement, co);
+            if (_data != undefined) {
                 _squadless.organise_by_template(_data, _squad_index, _empty_index, false);
</file context>
Suggested change
var _data = resolve_company_arrangement(obj_ini.chapter_squad_arrangement, co);
var _data = (co > 0) ? resolve_company_arrangement(obj_ini.chapter_squad_arrangement, co) : undefined;

var _found = false;
for (var ai = 0; ai < array_length(arrangement.companies); ai++) {
if (arrangement.companies[ai].company == _ovr.company) {
arrangement.companies[ai] = _ovr;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Company override entries are stored by reference, so editing live arrangement can mutate override templates unexpectedly.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/scr_squads/scr_squads.gml, line 925:

<comment>Company override entries are stored by reference, so editing live arrangement can mutate override templates unexpectedly.</comment>

<file context>
@@ -705,17 +858,115 @@ function UnitSquad(squad_type = undefined, company = 0) constructor {
+            var _found = false;
+            for (var ai = 0; ai < array_length(arrangement.companies); ai++) {
+                if (arrangement.companies[ai].company == _ovr.company) {
+                    arrangement.companies[ai] = _ovr;
+                    _found = true;
+                    break;
</file context>

Comment on lines +381 to +385
if (is_array(type)) {
show_debug_message($"[PROBE] change_type got ARRAY type (len {array_length(type)}): {type}");
} else if (!struct_exists(obj_ini.squad_types, type)) {
show_debug_message($"[PROBE] change_type unknown squad type: \"{type}\"");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Invalid squad types are detected but not stopped; function still dereferences the invalid key and can crash.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/scr_squads/scr_squads.gml, line 381:

<comment>Invalid squad types are detected but not stopped; function still dereferences the invalid key and can crash.</comment>

<file context>
@@ -279,6 +378,11 @@ function UnitSquad(squad_type = undefined, company = 0) constructor {
 
     static change_type = function(new_type) {
         type = new_type;
+        if (is_array(type)) {
+            show_debug_message($"[PROBE] change_type got ARRAY type (len {array_length(type)}): {type}");
+        } else if (!struct_exists(obj_ini.squad_types, type)) {
</file context>
Suggested change
if (is_array(type)) {
show_debug_message($"[PROBE] change_type got ARRAY type (len {array_length(type)}): {type}");
} else if (!struct_exists(obj_ini.squad_types, type)) {
show_debug_message($"[PROBE] change_type unknown squad type: \"{type}\"");
}
if (is_array(type)) {
show_debug_message($"[PROBE] change_type got ARRAY type (len {array_length(type)}): {type}");
return;
} else if (!struct_exists(obj_ini.squad_types, type)) {
show_debug_message($"[PROBE] change_type unknown squad type: \"{type}\"");
return;
}

@cubic-dev-ai cubic-dev-ai Bot dismissed their stale review June 30, 2026 20:35

Dismissed because Cubic found issues in a newer review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: JSON Changes to external JSON files or their under-the-hood functionality Area: Sprites Changes to sprites/images or their under-the-hood functionality Size: Warning Type: Feature Adds something new

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant