Ok I worked abit further on this script.
The good news is, the version in this post can hide all squad units and spawn one or more upgrade units to replace them.
It triggers for each Hero of this type and upgrades them. It also uses Register_Death_Event to cause the hidden units to make Harakiri after their upgrades were destroyed, so the Unit wont survive if their upgrade dies.
The bad news is it has drawbacks and glitches: If your Level 1 Unit is a Hero, and is limited to 1 - then the player can rebuild him after he hides, except if you set him to be <Build_Limit_Lifetime_Per_Player> 1, but then if the Harakiri function triggers to kill Level 1 after Level 2 was destroyed I fear the player wont be able to build a new one within the whole GC!
And if that hero has its icon dispayed I it isnt possible to hide that icon, the units will be hidden, but the icon will stay.
More bad news: There is a goddamn bug that always causes the game to crash after loading a savegame with hidden Units, it is a very critical bug, and I know it is caused by this line (it is used 2x)
Unit.Change_Owner(Neutral)
Usually Change owner shouldnt cause a crash between the savegames, but sometimes it does because of the context with other code.
I already tried to put it into another context, even into an other sate.. messed 4 hours with it, without any result ... so I gave up on this.
I could exit the script after 1 Upgrade, that would solve the loadcrash bug. But then the script wouldnt continue checking for the harakiri event to kill the Lv1 version, so that would always survive. Further the continous check is needed to make sure the Units stay hidden after reloading the savegames (usually but for this scirpit loading wont work anyway).
I also updated the other version of this script in the last post, it is able to handle squadrons now (actually it was even before, tiny changes). It will destroy the original hero and he wont stay for the GC and have to be rebuilt, but it works without crashing the game after each reload.
The only thing what you have to make sure is:
If your hero squadron has 1 leader unit and all other fighters are generic, put the hero into slot 1 of the table
Valid_Units, the upgrde unit to spawn in slot 2, and the generic fighters into slot 3. I only marked the
Spawn_Unit line to not spawn another unit for the other type of figher, you can use this principle to do it for as many fighter types you like.
@Locutus: Thank you for the code above, for my tests it didnt worked in the context of this script.
So now you can choose between these versions, here's the buggy one that hides:
--==================================================================================================
--**************************** Hero Upgrade Script ******************************
--==================================================================================================
--[[
<!-- You need to have this dummy unit 1x in any registered .xml: -->
<!-- === Used to prevent multiple usage of the lua code === -->
<MiscObject Name="Upgrade_Dummy">
<Text_ID/>
<Space_Model_Name>W_LASER_INVISIBLE.ALO</Space_Model_Name>
<Land_Model_Name>W_LASER_INVISIBLE.ALO</Land_Model_Name>
<Scale_Factor>1.0</Scale_Factor>
<Behavior>DUMMY_ORBITAL_STRUCTURE, SPACE_OBSTACLE, IDLE</Behavior>
<SpaceBehavior>ABILITY_COUNTDOWN, UNIT_AI, HUNT</SpaceBehavior>
<Layer_Z_Adjust>0.0</Layer_Z_Adjust>
<Sort_Order_Adjust>-1</Sort_Order_Adjust>
<Remove_Upon_Death>true</Remove_Upon_Death>
<Space_Layer> StaticObject </Space_Layer>
<Target_Stealth_Units>Yes</Target_Stealth_Units>
<Victory_Relevant>no</Victory_Relevant>
<Lua_Script>ObjectScript_Hero_Upgrade</Lua_Script>
</MiscObject>
<!-- Then please paste this Lua tag into any Upgrade .xml instance of UpgradeObjects.xml, or StarBase.xml -->
<Lua_Script>ObjectScript_Hero_Upgrade</Lua_Script>
<!-- Finally please insert VALID unit names into Valid_Units (2 replaces 1, 4 replaces 3, 6 replaces 5 and so on.. -->
<!-- Do it with caution, any misstyping in Valid_Units will crash the script!, and dont use Squadrons or HeroCompanys, UniqueUnits and SpaceShips/Ifantry is allowed -->
]]
-- We'll need to load this:
require("PGStateMachine")
require("PGStoryMode")
--=================== State Definitions ===================
function Definitions()
Define_State("State_Init", State_Init)
Define_State("State_Inactive", State_Inactive)
Valid_Units = {"Tauri_Hero_Mitchell_Fighter_Mitchell", "Tauri_Hero_Daedalus", "Tauri_Hero_Mitchell_Fighter"}
-- This is the Dummy Opgrade Unit we're going to use
Upgrade_Dummy_Name = "Upgrade_Dummy"
-- We'll need this table to know which units were hidden:
Hidden_Units = {}
-- Refreshing every 1 secs
ServiceRate = 0.1
Neutral = Find_Player("Neutral")
end
--=================== State_Init ===================
function State_Init(message)
if message == OnEnter then
-- We want only Regular Units to spawn 1 Upgrade_Dummy,
-- if this script is executed by a Upgrade_Dummy it will run through this state without doing anything
if Object.Get_Type() ~= Find_Object_Type(Upgrade_Dummy_Name) then
-- Getting all Units of this type
local Upgrade_Dummies = Find_All_Objects_Of_Type(Upgrade_Dummy_Name)
-- If there already is one Instance of this kind, this Script will Exit
if not TestValid(Upgrade_Dummies[1])
-- Making sure each fraction gets its own invisible Upgrade Dummy
or Upgrade_Dummies[1].Get_Owner() ~= Object.Get_Owner()
or Upgrade_Dummies[2].Get_Owner() ~= Object.Get_Owner()
or Upgrade_Dummies[3].Get_Owner() ~= Object.Get_Owner()
or Upgrade_Dummies[4].Get_Owner() ~= Object.Get_Owner() then
-- Otherwise we create one instance of it, so it runns... once ^^
Upgrade_Dummie = SpawnList({Upgrade_Dummy_Name}, Object, Object.Get_Owner(), true, true)
-- After spawning this dummy we can exit this script, its not longer needed.
ScriptExit()
else
ScriptExit()
end
end
-- Have to wait for stability reasons
Sleep (4.0)
-- If you wish to see the Dummy (for test purposes) uncomment this:
-- Object.Highlight(true)
Set_Next_State("State_Inactive")
end
end
--=================== State_Inactive ===================
function State_Inactive(message)
if message == OnUpdate then Sleep (10.0) -- Sleep 10 to refreach every 10 sec
-- === This part finds all valid Target Units and throws them into the table "Target_Unit" ===
-- (Re)innitiating Variable
Target_Unit = {}
-- Getting all Valid_Units instances on the map
for each, String_Name in pairs(Valid_Units) do
local Found_Units = Find_All_Objects_Of_Type(String_Name)
for each, Unit in pairs(Found_Units) do
-- If it still exists and has the player fraction
if TestValid(Unit) and Unit.Get_Owner() == Object.Get_Owner() then
-- Then we will insert it into the table of "Target_Unit"
table.insert(Target_Unit, Unit)
end
end
end
-- ==========================================
-- And finally we check this on every refresh for each unit in the Target_Unit list:
for each, Unit in pairs(Target_Unit) do
-- If still existing
if TestValid(Unit) then
-- === We Replace Valid_Units[1] with Valid_Units[2] ===
if Unit.Get_Type() == Find_Object_Type(Valid_Units[1]) then
-- Spawning Upgraded version to old position: param 1 = Unit, param 2 = Loaction, param 3 = Owner (Object Owner in this case)
Upgraded_Unit = Spawn_Unit(Find_Object_Type(Valid_Units[2]), Unit, Unit.Get_Owner())
Sleep (0.5)
-- Despawning old version after a short break
-- Unit.Despawn()
-- Preventing further damage that might destroy the ship
Unit.Make_Invulnerable(true)
Unit.Prevent_All_Fire(true)
-- Changing to neutral player because their radar icon isnt very good visible on minimap
Unit.Change_Owner(Neutral)
-- Unselect the unit so the select box wont show up.
Unit.Set_Selectable(false)
-- As soon the Evolved_State that represents this unit was destroyed, we'll call the suicide thread
Register_Death_Event(Find_First_Object(Valid_Units[2]), Make_Harakiri)
-- We'll need to insert Unit into this table to know which units were hidden:
table.insert(Hidden_Units, Unit)
-- === Replacing Valid_Units[3] with Valid_Units[4].. and so on ===
-- You can copy this part as often you like and change the values of Valid_Units[X] to upgrade more units
elseif Unit.Get_Type() == Find_Object_Type(Valid_Units[3]) then
-- Upgraded_Unit = Spawn_Unit(Find_Object_Type(Valid_Units[4]), Unit, Unit.Get_Owner())
Sleep (0.5)
-- Preventing further damage that might destroy the ship
Unit.Make_Invulnerable(true)
Unit.Prevent_All_Fire(true)
-- Changing to neutral player because their radar icon isnt very good visible on minimap
Unit.Change_Owner(Neutral)
-- Unselect the unit so the select box wont show up.
Unit.Set_Selectable(false)
-- We'll need to insert Unit into this table to know which units were hidden:
table.insert(Hidden_Units, Unit)
-- You can use wheter Despawn or paste the few lines above to hide the object instead
-- Commented out because causes Scriptcrash if is assigned to unused table slots:
--[[
elseif Unit.Get_Type() == Find_Object_Type(Valid_Units[5]) then
Upgraded_Unit = Spawn_Unit(Find_Object_Type(Valid_Units[6]), Unit, Unit.Get_Owner())
Sleep (0.5)
Unit.Despawn()
elseif Unit.Get_Type() == Find_Object_Type(Valid_Units[7]) then
Upgraded_Unit = Spawn_Unit(Find_Object_Type(Valid_Units[8]), Unit, Unit.Get_Owner())
Sleep (0.5)
Unit.Despawn()
]]
end
end
end
-- ======= Making sure hidden units stay hidden =======
for each, Unit in pairs(Hidden_Units) do
-- After upgrading the fighter it will stay in this state and check to hide itself after loading a game.
if TestValid(Unit) then
-- Hiding the Object (not Despawning it because in GC Mode otherwise it would disappear)
Hide_Object(Unit, 1)
end
end
-- For testpurposes, to know when a cycle ends:
-- Object.Get_Owner().Give_Money(1000)
end
end
--=================================== Threads ===================================
-- When triggered our Object will make Harakiri
function Make_Harakiri()
for each, Unit in pairs(Hidden_Units) do
Unit.Despawn()
end
-- Clearing Variable
Hidden_Units = {}
end
--=================== End of File ===================