Sidemod crashing once NPC units spawn

Started by SPS-barbarossa, February 14, 2026, 01:39:11 AM

Previous topic - Next topic
Hi all,

I am working on a sidemod that aims to bring more gameplay variety to the factions/classes. I want to squeeze much gameplay out of SWBF1 without importing any external assets.

So far, it's been going great! But I ran into some issues that I have not been able troubleshoot:

Whenever I import a new class into the game and it replaces the wookie smuggler it crashes. But if said new class replaces the marksman class, the game runs without issue. The same thing happens after removing a grenade from "all_inf_soldier.odf". In both cases the crash occured as soon as NPCs spawned into the map.

For this mod I've only edited the MISSION.LVL for TAT2 and the SIDES.LVL for the game.

Any ideas of what could trigger these crashes?

Thanks for your time!

Go ahead and share your mission.lvl lua changes here, and we'll see what we can figure out with them.
The BOBclan:  A Rich History


Quote from: Unit 33 on November 29, 2014, 03:44:44 AM'Please, tell me more about the logistics of the design of laser swords being wielded by space wizards' - Some guy on the internet.

Quote from: Dark_Phantom on February 16, 2026, 04:26:07 PMGo ahead and share your mission.lvl lua changes here, and we'll see what we can figure out with them.

Thanks for reaching out and wanting to check my code

The new class is called "all_inf_flanker", here are the mission.lvl changes I made to tat2i.lua.

---------------------------------------------------------------------------
-- FUNCTION:    ScriptInit
-- PURPOSE:     This function is only run once
-- INPUT:
-- OUTPUT:
-- NOTES:       The name, 'ScriptInit' is a chosen convention, and each
--              mission script must contain a version of this function, as
--              it is called from C to start the mission.
---------------------------------------------------------------------------

function ScriptInit()
--  Empire Attacking (attacker is always #1)
    local ALL = 2
    local IMP = 1
--  These variables do not change
    local ATT = 1
    local DEF = 2

    AddMissionObjective(IMP, "red", "level.tat2.objectives.1");
--  AddMissionObjective(IMP, "orange", "level.tat2.objectives.2");
    AddMissionObjective(ALL, "red", "level.tat2.objectives.1");
--  AddMissionObjective(ALL, "orange", "level.tat2.objectives.3");

SetTeamAggressiveness(IMP, 0.95)
SetTeamAggressiveness(ALL, 0.95)

SetMaxFlyHeight(50);
--    SetMaxFlyHeight(40);

    ReadDataFile("sound\\tat.lvl;tat2gcw");
    ReadDataFile("SIDE\\all.lvl",
        "all_inf_basicdesert",
        "all_inf_lukeskywalker",
--        "all_inf_smuggler")
    "all_inf_flanker");


    ReadDataFile("SIDE\\imp.lvl",
        "imp_fly_destroyer_dome",
        "imp_walk_atst",
        "imp_inf_basic",
        "imp_inf_dark_trooper",
        "imp_inf_darthvader");
    ReadDataFile("SIDE\\des.lvl",
        "tat_inf_jawa");
--      Alliance Stats
    SetTeamName(ALL, "Alliance")
    SetTeamIcon(ALL, "all_icon")
    AddUnitClass(ALL, "all_inf_soldierdesert",11)
    AddUnitClass(ALL, "all_inf_vanguard",3)
    AddUnitClass(ALL, "all_inf_pilot",4)
    AddUnitClass(ALL, "all_inf_marksman",4)
--    AddUnitClass(ALL, "all_inf_smuggler",3)
    AddUnitClass(ALL, "all_inf_flanker",3)
    SetHeroClass(ALL, "all_inf_lukeskywalker")

--      Imperial Stats
    SetTeamName(IMP, "Empire")
    SetTeamIcon(IMP, "imp_icon")
    AddUnitClass(IMP, "imp_inf_storm_trooper",11)
    AddUnitClass(IMP, "imp_inf_shock_trooper",3)
    AddUnitClass(IMP, "imp_inf_pilotatst",4)
    AddUnitClass(IMP, "imp_inf_scout_trooper",4)
    AddUnitClass(IMP, "imp_inf_dark_trooper",3)
    SetHeroClass(IMP, "imp_inf_darthvader")

--  Attacker Stats
    SetUnitCount(ATT, 25)
    SetReinforcementCount(ATT, 250)
--    SetReinforcementCount(ATT, 200)
    AddBleedThreshold(ATT, 31, 0.0)
    AddBleedThreshold(ATT, 21, 0.75)
    AddBleedThreshold(ATT, 11, 2.25)
    AddBleedThreshold(ATT, 1, 3.0)
    SetTeamAsFriend(ATT, 3)

--  Defender Stats
    SetUnitCount(DEF, 25)
    SetReinforcementCount(DEF, 250)
--    SetReinforcementCount(DEF, 200)
    AddBleedThreshold(DEF, 31, 0.0)
    AddBleedThreshold(DEF, 21, 0.75)
    AddBleedThreshold(DEF, 11, 2.25)
    AddBleedThreshold(DEF, 1, 3.0)
    SetTeamAsFriend(DEF, 3)

--  Local Stats
    SetTeamName (3, "locals")
    AddUnitClass (3, "tat_inf_jawa", 14);
    SetUnitCount (3, 14)
    SetTeamAsFriend(3,ATT)
    SetTeamAsFriend(3,DEF)

--  Level Stats
    ClearWalkers()
    AddWalkerType(0, 0) -- special -> droidekas
    AddWalkerType(1, 1) -- 1x2 (1 pair of legs)
    AddWalkerType(2, 0) -- 2x2 (2 pairs of legs)
    AddWalkerType(3, 0) -- 3x2 (3 pairs of legs)
    SetMemoryPoolSize("Obstacle", 653)
    SetSpawnDelay(10.0, 0.25)
    ReadDataFile("TAT\\tat2.lvl")
    SetDenseEnvironment("false")


--  Sound Stats
    OpenAudioStream("sound\\tat.lvl",  "tatgcw_music");
    OpenAudioStream("sound\\tat.lvl",  "tat2");
    OpenAudioStream("sound\\tat.lvl",  "tat2");
    OpenAudioStream("sound\\gcw.lvl",  "gcw_vo");
    OpenAudioStream("sound\\gcw.lvl",  "gcw_tac_vo");

    SetBleedingVoiceOver(ALL, ALL, "all_off_com_report_us_overwhelmed", 1);
    SetBleedingVoiceOver(ALL, IMP, "all_off_com_report_enemy_losing",   1);
    SetBleedingVoiceOver(IMP, ALL, "imp_off_com_report_enemy_losing",   1);
    SetBleedingVoiceOver(IMP, IMP, "imp_off_com_report_us_overwhelmed", 1);

    SetLowReinforcementsVoiceOver(ALL, ALL, "all_off_defeat_im", .1, 1);
    SetLowReinforcementsVoiceOver(ALL, IMP, "all_off_victory_im", .1, 1);
    SetLowReinforcementsVoiceOver(IMP, IMP, "imp_off_defeat_im", .1, 1);
    SetLowReinforcementsVoiceOver(IMP, ALL, "imp_off_victory_im", .1, 1);

    SetOutOfBoundsVoiceOver(2, "Allleaving");
    SetOutOfBoundsVoiceOver(1, "Impleaving");

    SetAmbientMusic(ALL, 1.0, "all_tat_amb_start",  0,1);
    SetAmbientMusic(ALL, 0.99, "all_tat_amb_middle", 1,1);
    SetAmbientMusic(ALL, 0.1,"all_tat_amb_end",    2,1);
    SetAmbientMusic(IMP, 1.0, "imp_tat_amb_start",  0,1);
    SetAmbientMusic(IMP, 0.99, "imp_tat_amb_middle", 1,1);
    SetAmbientMusic(IMP, 0.1,"imp_tat_amb_end",    2,1);

    SetVictoryMusic(ALL, "all_tat_amb_victory");
    SetDefeatMusic (ALL, "all_tat_amb_defeat");
    SetVictoryMusic(IMP, "imp_tat_amb_victory");
    SetDefeatMusic (IMP, "imp_tat_amb_defeat");

    SetSoundEffect("ScopeDisplayZoomIn",  "binocularzoomin");
    SetSoundEffect("ScopeDisplayZoomOut", "binocularzoomout");
    --SetSoundEffect("WeaponUnableSelect",  "com_weap_inf_weaponchange_null");
    --SetSoundEffect("WeaponModeUnableSelect",  "com_weap_inf_modechange_null");
    SetSoundEffect("SpawnDisplayUnitChange",       "shell_select_unit");
    SetSoundEffect("SpawnDisplayUnitAccept",       "shell_menu_enter");
    SetSoundEffect("SpawnDisplaySpawnPointChange", "shell_select_change");
    SetSoundEffect("SpawnDisplaySpawnPointAccept", "shell_menu_enter");
    SetSoundEffect("SpawnDisplayBack",             "shell_menu_exit");

    SetPlanetaryBonusVoiceOver(IMP, IMP, 0, "imp_bonus_imp_medical");
    SetPlanetaryBonusVoiceOver(IMP, ALL, 0, "imp_bonus_all_medical");
    SetPlanetaryBonusVoiceOver(IMP, IMP, 1, "");
    SetPlanetaryBonusVoiceOver(IMP, ALL, 1, "");
    SetPlanetaryBonusVoiceOver(IMP, IMP, 2, "imp_bonus_imp_sensors");
    SetPlanetaryBonusVoiceOver(IMP, ALL, 2, "imp_bonus_all_sensors");
    SetPlanetaryBonusVoiceOver(IMP, IMP, 3, "imp_bonus_imp_hero");
    SetPlanetaryBonusVoiceOver(IMP, ALL, 3, "imp_bonus_all_hero");
    SetPlanetaryBonusVoiceOver(IMP, IMP, 4, "imp_bonus_imp_reserves");
    SetPlanetaryBonusVoiceOver(IMP, ALL, 4, "imp_bonus_all_reserves");
    SetPlanetaryBonusVoiceOver(IMP, IMP, 5, "imp_bonus_imp_sabotage");--sabotage
    SetPlanetaryBonusVoiceOver(IMP, ALL, 5, "imp_bonus_all_sabotage");
    SetPlanetaryBonusVoiceOver(IMP, IMP, 6, "");
    SetPlanetaryBonusVoiceOver(IMP, ALL, 6, "");
    SetPlanetaryBonusVoiceOver(IMP, IMP, 7, "imp_bonus_imp_training");--advanced training
    SetPlanetaryBonusVoiceOver(IMP, ALL, 7, "imp_bonus_all_training");--advanced training

    SetPlanetaryBonusVoiceOver(ALL, ALL, 0, "all_bonus_all_medical");
    SetPlanetaryBonusVoiceOver(ALL, IMP, 0, "all_bonus_imp_medical");
    SetPlanetaryBonusVoiceOver(ALL, ALL, 1, "");
    SetPlanetaryBonusVoiceOver(ALL, IMP, 1, "");
    SetPlanetaryBonusVoiceOver(ALL, ALL, 2, "all_bonus_all_sensors");
    SetPlanetaryBonusVoiceOver(ALL, IMP, 2, "all_bonus_imp_sensors");
    SetPlanetaryBonusVoiceOver(ALL, ALL, 3, "all_bonus_all_hero");
    SetPlanetaryBonusVoiceOver(ALL, IMP, 3, "all_bonus_imp_hero");
    SetPlanetaryBonusVoiceOver(ALL, ALL, 4, "all_bonus_all_reserves");
    SetPlanetaryBonusVoiceOver(ALL, IMP, 4, "all_bonus_imp_reserves");
    SetPlanetaryBonusVoiceOver(ALL, ALL, 5, "all_bonus_all_sabotage");--sabotage
    SetPlanetaryBonusVoiceOver(ALL, IMP, 5, "all_bonus_imp_sabotage");
    SetPlanetaryBonusVoiceOver(ALL, ALL, 6, "");
    SetPlanetaryBonusVoiceOver(ALL, IMP, 6, "");
    SetPlanetaryBonusVoiceOver(ALL, ALL, 7, "all_bonus_all_training");--advanced training
    SetPlanetaryBonusVoiceOver(ALL, IMP, 7, "all_bonus_imp_training");--advanced training

    SetAttackingTeam(ATT);

--  Camera Stats
--Tat2 Mos Eisley
--Overhead
AddCameraShot(0.514878, -0.143332, -0.814235, -0.226667, -351.052490, 31.599720, -71.300522);
--Derelict
AddCameraShot(0.899316, 0.007445, 0.437220, -0.003620, -212.966995, 20.173393, 56.179829);
--Cantina
AddCameraShot(0.902993, -0.019975, -0.429085, -0.009492, -205.001770, 17.679758, 77.177254);
end

Since my first message I did some experimentation and found that replacing the darktrooper class posed no problems. The game kept running and the NPCs played the new class without issue. So I am puzzled as to why editing the smuggler and rebel trooper classes (or their loadout) causes issues.

Just before writing this reply I tested it again just to be sure. It crashes as soon as the NPCs join, but in an PVP LAN match the class is fully playable without issue.

Thanks again for taking the time :)

You need a "dc" infront of your SIDE\\all.lvl.
The ReadDataFile function specifies a filepath.
If no dc is put infront the default all.lvl is loaded. Because the default lvl does not know about the flanker it crashes.

Ah I see, could you give an example of what the syntax would look like? Or an existing forum thread that goes into more detail? Because I tried several things like:

ReadDataFile("DC:SIDE\\all.lvl"

ReadDataFile("dc\\SIDE\\all.lvl"

ReadDataFile("dc\SIDE\\all.lvl"

And all of them resulted in crashes.

Sorry, should have been more specific.
Your first guess is right.
However, that should not be the problem since you were able to replace the marksman with the new unit.
I initially misread your first post.

ReadDataFile("dc:SIDE\\all.lvl"

How exactly have you set up your project?
Do you add the new unit class to the all.req file and copy the munged all.lvl file over to the GameData/Data/lvl_pc/Sides/ folder?
Or did you munge the tat2 map and use it from the addon folder?



Regarding your changes to the soldier class: It would be helpful to see what lines you changed in the odf.

Quote from: {AR}MetalKiller on Today at 07:09:01 AMHow exactly have you set up your project?
Do you add the new unit class to the all.req file and copy the munged all.lvl file over to the GameData/Data/lvl_pc/Sides/ folder?
Or did you munge the tat2 map and use it from the addon folder?

Yes,I have added the unit to the all.req file and created the file inside the "REQ" folder. Inside the ODF folder I've created the unit itself. After munging I have copied the file ALL.LVL into the "GameData/Data/lvl_pc/Sides/" folder. With this technique I've already created a new unit replacing the darktrooper and modified other ODF values, this works perfectly fine. (and has been a ton of fun)

I did not munge TAT2 into my addon folder.


To give some more context about my process: I run game version 1.3.7 GOG, I have created the mod using BFbuilder pro and us it to munge the SIDE LVLs. The mission.LVL I made using battlebektoolbox.

Quote from: {AR}MetalKiller on Today at 07:09:01 AMRegarding your changes to the soldier class: It would be helpful to see what lines you changed in the odf.

These are the only lines I changed and causes the crashes once NPCs spawn. Once I undo these changes the game runs fine again. I've tested this 5+ times.
The oddd thing is that if for example I use the same method to remove the mines from the vanguard, there are no issues whatsoever.

WeaponName1         = "all_weap_inf_rifle"
WeaponAmmo1         = 6
WeaponName2         = "all_weap_inf_pistol"
WeaponAmmo2         = 0
WeaponName3         = "all_weap_inf_thermaldetonator"
WeaponAmmo3         = 3
WeaponChannel3        = 1
//WeaponName4         = "all_weap_inf_crackgrenade"
//WeaponAmmo4         = 3
//WeaponChannel4    = 1

I am starting to think that some AI routine is looking at the loadouts of several classes (rebel soldier, smuggler) and once some classes are changed, they're no longer compatible with the AI routine.

Today at 08:59:48 AM #7 Last Edit: Today at 09:02:55 AM by Dark_Phantom
Let me make sure you've got your reqs set up correctly, I actually don't think this is the problem because AddUnitClass does NOT crash on load but it's good to check.
  • In All.req you added all_inf_flanker correctly
  • In the REQs folder, you created the file "all_inf_flanker.req"
  • In that file, you formatted it somewhat like this:
ucft
{
REQN
{
"class"
"all_inf_flanker"
}
}

Then:
  • You have an odf of all_inf_flanker.odf
  • All of your weapons on all_inf_flanker have valid odfs.
  • All of your meshs on all_inf_flanker are working.

Crashing when NPCs spawn or you attempt to select it (Can't tell if you tested this) means that something with that class is messed up specifically.  Either the weapons or the class itself could be the culprit.

Let me know what you find next.
The BOBclan:  A Rich History


Quote from: Unit 33 on November 29, 2014, 03:44:44 AM'Please, tell me more about the logistics of the design of laser swords being wielded by space wizards' - Some guy on the internet.