forked from Mirrors/openclonk
Add AI attack mode (weapon) to editor properties
parent
60f3e206cc
commit
da4f49d7ca
|
@ -0,0 +1,5 @@
|
|||
[DefCore]
|
||||
id=AI_AttackModes
|
||||
Version=8,0
|
||||
Category=C4D_StaticBack
|
||||
HideInCreator=true
|
|
@ -0,0 +1,176 @@
|
|||
/**
|
||||
AI Attack Modes
|
||||
Initializes the AI to have different weapons and attack scripts
|
||||
|
||||
@author Sven2
|
||||
*/
|
||||
|
||||
// Set attack mode / spell to control attack behaviour
|
||||
public func SetAttackMode(object clonk, string attack_mode_identifier)
|
||||
{
|
||||
if (GetType(this) != C4V_Def)
|
||||
Log("WARNING: SetAttackMode(%v, %s) not called from definition context but from %v", clonk, attack_mode_identifier, this);
|
||||
var fx_ai = this->GetAI(clonk);
|
||||
if (!fx_ai)
|
||||
return false;
|
||||
var attack_mode = this.AttackModes[attack_mode_identifier];
|
||||
if (!attack_mode)
|
||||
return Log("Attack mode %s does not exist.", attack_mode_identifier);
|
||||
// Stop previous attack mode
|
||||
if (fx_ai.attack_mode && fx_ai.attack_mode.Destruction) Call(fx_ai.attack_mode.Destruction, fx_ai);
|
||||
// Set new
|
||||
fx_ai.attack_mode = attack_mode;
|
||||
if (fx_ai.attack_mode.Construction) Call(fx_ai.attack_mode.Construction, fx_ai);
|
||||
// Remember inventory to be destroyed on death
|
||||
this->BindInventory(clonk);
|
||||
return true;
|
||||
}
|
||||
|
||||
local AttackModes;
|
||||
|
||||
// Attack mode that just creates a weapon and uses the default attack procedures
|
||||
local SingleWeaponAttackMode = {
|
||||
Construction = func(effect fx)
|
||||
{
|
||||
var weapon = fx.Target->CreateContents(fx.attack_mode.Weapon);
|
||||
if (weapon)
|
||||
{
|
||||
if (fx.attack_mode.Ammo)
|
||||
{
|
||||
var ammo = weapon->CreateContents(fx.attack_mode.Ammo);
|
||||
if (ammo) ammo->~SetInfiniteStackCount();
|
||||
}
|
||||
// Do not save in scenario, because it's automatically created through the attack mode setting
|
||||
AddEffect("IntNoScenarioSave", weapon, 1);
|
||||
// Automatic fadeout+inventory respawn of e.g. firestones
|
||||
if (fx.attack_mode.Respawn)
|
||||
{
|
||||
weapon->~SetStackCount(1); // Ensure departure is called on every object
|
||||
weapon.Departure = AI.Departure_WeaponRespawn;
|
||||
}
|
||||
}
|
||||
},
|
||||
Destruction = func(effect fx)
|
||||
{
|
||||
var weapon = fx.Target->FindContents(fx.attack_mode.Weapon);
|
||||
if (weapon) weapon->RemoveObject();
|
||||
},
|
||||
FindWeapon = func(effect fx)
|
||||
{
|
||||
if (!(fx.weapon = fx.Target->FindContents(fx.attack_mode.Weapon))) return false;
|
||||
fx.strategy = fx.attack_mode.Strategy;
|
||||
return true;
|
||||
},
|
||||
GetName = func()
|
||||
{
|
||||
if (this.Ammo)
|
||||
return Format("%s (%s)", this.Weapon->GetName(), this.Ammo->GetName());
|
||||
else
|
||||
return this.Weapon->GetName();
|
||||
},
|
||||
GetEditorHelp = func()
|
||||
{
|
||||
if (this.Ammo)
|
||||
return Format("$AttackWithAmmo$", this.Weapon->GetName(), this.Ammo->GetName());
|
||||
else
|
||||
return Format("$AttackWith$", this.Weapon->GetName());
|
||||
}
|
||||
};
|
||||
|
||||
private func InitAttackModes()
|
||||
{
|
||||
// First-time init of attack mode editor prop structures
|
||||
if (!this.AttackModes)
|
||||
{
|
||||
// All attack modes structures point to the base AI
|
||||
if (!AI.AttackModes) AI.AttackModes = {};
|
||||
if (this != AI) this.AttackModes = AI.AttackModes;
|
||||
}
|
||||
if (!AI.FxAI.EditorProps.attack_mode)
|
||||
{
|
||||
AI.FxAI.EditorProps.attack_mode = {
|
||||
Name="$AttackMode$",
|
||||
EditorHelp="$AttackModeHelp$",
|
||||
Type="enum",
|
||||
Sorted=true,
|
||||
Options=[],
|
||||
Set="SetAttackMode"
|
||||
};
|
||||
}
|
||||
if (!this.FxAI.EditorProps.attack_mode) this.FxAI.EditorProps.attack_mode = AI.FxAI.EditorProps.attack_mode;
|
||||
}
|
||||
|
||||
public func RegisterAttackMode(string identifier, proplist am)
|
||||
{
|
||||
// Definition call during Definition()-initialization:
|
||||
// Register a new attack mode selectable for the AI clonk
|
||||
// Add to attack mode info structure
|
||||
if (!AttackModes) this->InitAttackModes();
|
||||
AttackModes[identifier] = am;
|
||||
am.Identifier = identifier;
|
||||
// Add to editor option for AI effect
|
||||
var am_option = {
|
||||
Name = am.Name ?? am->GetName(),
|
||||
EditorHelp = am.EditorHelp,
|
||||
Value = am
|
||||
};
|
||||
if (!am_option.EditorHelp && am.GetEditorHelp) am_option.EditorHelp = am->GetEditorHelp();
|
||||
var editor_opts = this.FxAI.EditorProps.attack_mode.Options;
|
||||
editor_opts[GetLength(editor_opts)] = am_option;
|
||||
}
|
||||
|
||||
private func DefinitionAttackModes(proplist def)
|
||||
{
|
||||
// Register presets for all the default weapons usable by the AI
|
||||
this->InitAttackModes();
|
||||
// Registration only once for base AI
|
||||
if (this != AI) return;
|
||||
def->RegisterAttackMode("Default", { Name = "$Default$", EditorHelp = "$DefaultHelp$", FindWeapon = AI.FindInventoryWeapon });
|
||||
def->RegisterAttackMode("Sword", new SingleWeaponAttackMode { Weapon = Sword, Strategy = this.ExecuteMelee });
|
||||
def->RegisterAttackMode("Club", new SingleWeaponAttackMode { Weapon = Club, Strategy = this.ExecuteMelee });
|
||||
def->RegisterAttackMode("Axe", new SingleWeaponAttackMode { Weapon = Axe, Strategy = this.ExecuteMelee });
|
||||
def->RegisterAttackMode("BowArrow", new SingleWeaponAttackMode { Weapon = Bow, Ammo = Arrow, FindWeapon = this.FindInventoryWeaponBow });
|
||||
def->RegisterAttackMode("BowFireArrow", new SingleWeaponAttackMode { Weapon = Bow, Ammo = FireArrow, FindWeapon = this.FindInventoryWeaponBow });
|
||||
def->RegisterAttackMode("BowBombArrow", new SingleWeaponAttackMode { Weapon = Bow, Ammo = BombArrow, FindWeapon = this.FindInventoryWeaponBow });
|
||||
def->RegisterAttackMode("GrenadeLauncher", new SingleWeaponAttackMode { Weapon = GrenadeLauncher, Ammo = IronBomb, FindWeapon = this.FindInventoryWeaponGrenadeLauncher });
|
||||
def->RegisterAttackMode("Blunderbuss", new SingleWeaponAttackMode { Weapon = Blunderbuss, Ammo = LeadBullet, FindWeapon = this.FindInventoryWeaponBlunderbuss });
|
||||
def->RegisterAttackMode("Javelin", new SingleWeaponAttackMode { Weapon = Javelin, Respawn = true, FindWeapon = this.FindInventoryWeaponJavelin });
|
||||
def->RegisterAttackMode("Rock", new SingleWeaponAttackMode { Weapon = Rock, Respawn = true, Strategy = this.ExecuteThrow });
|
||||
def->RegisterAttackMode("Firestone", new SingleWeaponAttackMode { Weapon = Firestone, Respawn = true, Strategy = this.ExecuteThrow });
|
||||
def->RegisterAttackMode("Lantern", new SingleWeaponAttackMode { Weapon = Lantern, Respawn = true, Strategy = this.ExecuteThrow });
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Attack with respawning weapons */
|
||||
|
||||
func Departure_WeaponRespawn(object container)
|
||||
{
|
||||
// Weapon used? Schedule to respawn a new one!
|
||||
if (container->GetAlive() || container->GetID()==Catapult)
|
||||
{
|
||||
container->ScheduleCall(container, AI_AttackModes.DoWeaponRespawn, 5, 1, GetID());
|
||||
}
|
||||
// Remove this weapon after a while
|
||||
// (This function should be save to be called in foreign context)
|
||||
ScheduleCall(this, Rule_ObjectFade.FadeOutObject, 120, 1, this);
|
||||
// No double-respawn in case it gets collected
|
||||
this.Departure = nil;
|
||||
}
|
||||
|
||||
func DoWeaponRespawn(id_weapon)
|
||||
{
|
||||
if (GetAlive() || GetID()==Catapult)
|
||||
{
|
||||
var re_weapon = CreateContents(id_weapon);
|
||||
if (re_weapon)
|
||||
{
|
||||
re_weapon->~SetStackCount(1); // Ensure departure is called on every object
|
||||
re_weapon.Departure = AI_AttackModes.Departure_WeaponRespawn;
|
||||
// Do not save in scenario, because it's automatically created through the attack mode setting
|
||||
AddEffect("IntNoScenarioSave", re_weapon, 1);
|
||||
}
|
||||
return re_weapon;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
AttackMode=Waffe
|
||||
AttackModeHelp=Legt die Waffe und den Angriffsmodus dieses KI-Gegners fest.
|
||||
Default=Automatisch
|
||||
DefaultHelp=Benutzt immer die beste Waffe im Inventar.
|
||||
AttackWith=Angriff mit %s.
|
||||
AttackWithAmmo=Angriff mit %s und %s.
|
|
@ -0,0 +1,6 @@
|
|||
AttackMode=Weapon
|
||||
AttackModeHelp=Selects the weapon and attack mode of this AI enemy.
|
||||
Default=Automatic
|
||||
DefaultHelp=Always uses the best weapon in the Clonk's inventory.
|
||||
AttackWith=Attack with %s.
|
||||
AttackWithAmmo=Attack with %s and %s.
|
|
@ -19,6 +19,7 @@
|
|||
#include AI_RangedWeapons
|
||||
#include AI_TargetFinding
|
||||
#include AI_Vehicles
|
||||
#include AI_AttackModes
|
||||
|
||||
|
||||
// AI Settings.
|
||||
|
@ -58,7 +59,7 @@ public func AddAI(object clonk)
|
|||
if (!fx_ai)
|
||||
return;
|
||||
// Add AI default settings.
|
||||
BindInventory(clonk);
|
||||
SetAttackMode(clonk, "Default"); // also binds inventory
|
||||
SetHome(clonk);
|
||||
SetGuardRange(clonk, fx_ai.home_x - this.GuardRangeX, fx_ai.home_y - this.GuardRangeY, this.GuardRangeX * 2, this.GuardRangeY * 2);
|
||||
SetMaxAggroDistance(clonk, this.MaxAggroDistance);
|
||||
|
@ -225,8 +226,6 @@ local FxAI = new Effect
|
|||
this.Interval = 3;
|
||||
// Store the definition that controls this AI.
|
||||
this.control = control_def;
|
||||
// Init editor properties.
|
||||
this->InitEditorProps();
|
||||
// Store the vehicle the AI is using.
|
||||
if (this.Target->GetProcedure() == "PUSH")
|
||||
this.vehicle = this.Target->GetActionTarget();
|
||||
|
@ -276,17 +275,6 @@ local FxAI = new Effect
|
|||
this.alert = this.time;
|
||||
return dmg;
|
||||
},
|
||||
|
||||
InitEditorProps = func()
|
||||
{
|
||||
// Editor properties for the AI.
|
||||
this.EditorProps = {};
|
||||
this.EditorProps.guard_range = { Name = "$GuardRange$", Type = "rect", Storage = "proplist", Color = 0xff00, Relative = false };
|
||||
this.EditorProps.ignore_allies = { Name = "$IgnoreAllies$", Type = "bool" };
|
||||
this.EditorProps.max_aggro_distance = { Name = "$MaxAggroDistance$", Type = "circle", Color = 0x808080 };
|
||||
this.EditorProps.active = { Name = "$Active$", EditorHelp = "$ActiveHelp$", Type = "bool", Priority = 50, AsyncGet = "GetActive", Set = "SetActive" };
|
||||
this.EditorProps.auto_search_target = { Name = "$AutoSearchTarget$", EditorHelp = "$AutoSearchTargetHelp$", Type = "bool" };
|
||||
},
|
||||
SetActive = func(bool active)
|
||||
{
|
||||
this.Interval = 3 * active;
|
||||
|
@ -295,7 +283,17 @@ local FxAI = new Effect
|
|||
{
|
||||
return this.Interval != 0;
|
||||
},
|
||||
|
||||
SetAttackMode = func(proplist attack_mode)
|
||||
{
|
||||
return this.control->SetAttackMode(this.Target, attack_mode.Identifier);
|
||||
},
|
||||
EditorProps = {
|
||||
guard_range = { Name = "$GuardRange$", Type = "rect", Storage = "proplist", Color = 0xff00, Relative = false },
|
||||
ignore_allies = { Name = "$IgnoreAllies$", Type = "bool" },
|
||||
max_aggro_distance = { Name = "$MaxAggroDistance$", Type = "circle", Color = 0x808080 },
|
||||
active = { Name = "$Active$", EditorHelp = "$ActiveHelp$", Type = "bool", Priority = 50, AsyncGet = "GetActive", Set = "SetActive" },
|
||||
auto_search_target = { Name = "$AutoSearchTarget$", EditorHelp = "$AutoSearchTargetHelp$", Type = "bool" }
|
||||
},
|
||||
// Save this effect and the AI for scenarios.
|
||||
SaveScen = func(proplist props)
|
||||
{
|
||||
|
@ -304,6 +302,8 @@ local FxAI = new Effect
|
|||
props->AddCall("AI", this.control, "AddAI", this.Target);
|
||||
if (!this.Interval)
|
||||
props->AddCall("AI", this.control, "SetActive", this.Target, false);
|
||||
if (this.attack_mode.Identifier != "Default")
|
||||
props->AddCall("AI", this.control, "SetAttackMode", this.Target, Format("%v", this.attack_mode.Identifier));
|
||||
if (this.home_x != this.Target->GetX() || this.home_y != this.Target->GetY() || this.home_dir != this.Target->GetDir())
|
||||
props->AddCall("AI", this.control, "SetHome", this.Target, this.home_x, this.home_y, GetConstantNameByValueSafe(this.home_dir, "DIR_"));
|
||||
props->AddCall("AI", this.control, "SetGuardRange", this.Target, this.guard_range.x, this.guard_range.y, this.guard_range.wdt, this.guard_range.hgt);
|
||||
|
@ -478,9 +478,10 @@ public func ExecuteArm(effect fx)
|
|||
{
|
||||
// Find shield.
|
||||
fx.shield = fx.Target->FindContents(Shield);
|
||||
// Find a weapon. For now, just search own inventory.
|
||||
if (this->FindInventoryWeapon(fx) && fx.weapon->Contained() == fx.Target)
|
||||
// Find a weapon. Depends on attack mode
|
||||
if (Call(fx.attack_mode.FindWeapon, fx))
|
||||
{
|
||||
// Select unless it's e.g. a vehicle or a spell
|
||||
SelectItem(fx, fx.weapon);
|
||||
return true;
|
||||
}
|
||||
|
@ -506,57 +507,10 @@ public func FindInventoryWeapon(effect fx)
|
|||
else
|
||||
fx.weapon = nil;
|
||||
}
|
||||
if (fx.weapon = fx.Target->FindContents(GrenadeLauncher))
|
||||
{
|
||||
if (this->HasBombs(fx, fx.weapon))
|
||||
{
|
||||
fx.strategy = this.ExecuteRanged;
|
||||
fx.projectile_speed = 75;
|
||||
fx.aim_wait = 85;
|
||||
fx.ammo_check = this.HasBombs;
|
||||
fx.ranged = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
fx.weapon = nil;
|
||||
}
|
||||
if (fx.weapon = fx.Target->FindContents(Bow))
|
||||
{
|
||||
if (this->HasArrows(fx, fx.weapon))
|
||||
{
|
||||
fx.strategy = this.ExecuteRanged;
|
||||
fx.projectile_speed = 100;
|
||||
fx.aim_wait = 0;
|
||||
fx.ammo_check = this.HasArrows;
|
||||
fx.ranged = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
fx.weapon = nil;
|
||||
}
|
||||
if (fx.weapon = fx.Target->FindContents(Blunderbuss))
|
||||
{
|
||||
if (this->HasAmmo(fx, fx.weapon))
|
||||
{
|
||||
fx.strategy = this.ExecuteRanged;
|
||||
fx.projectile_speed = 200;
|
||||
fx.aim_wait = 85;
|
||||
fx.ammo_check = this.HasAmmo;
|
||||
fx.ranged = true;
|
||||
fx.ranged_direct = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
fx.weapon = nil;
|
||||
}
|
||||
if (fx.weapon = fx.Target->FindContents(Javelin))
|
||||
{
|
||||
fx.strategy = this.ExecuteRanged;
|
||||
fx.projectile_speed = fx.Target.ThrowSpeed * fx.weapon.shooting_strength / 100;
|
||||
fx.aim_wait = 16;
|
||||
fx.ranged=true;
|
||||
return true;
|
||||
}
|
||||
if (FindInventoryWeaponGrenadeLauncher(fx)) return true;
|
||||
if (FindInventoryWeaponBlunderbuss(fx)) return true;
|
||||
if (FindInventoryWeaponBow(fx)) return true;
|
||||
if (FindInventoryWeaponJavelin(fx)) return true;
|
||||
// Throwing weapons.
|
||||
if ((fx.weapon = fx.Target->FindContents(Firestone)) || (fx.weapon = fx.Target->FindContents(Rock)) || (fx.weapon = fx.Target->FindContents(Lantern)))
|
||||
{
|
||||
|
@ -573,6 +527,73 @@ public func FindInventoryWeapon(effect fx)
|
|||
return false;
|
||||
}
|
||||
|
||||
private func FindInventoryWeaponGrenadeLauncher(effect fx)
|
||||
{
|
||||
if (fx.weapon = fx.Target->FindContents(GrenadeLauncher))
|
||||
{
|
||||
if (this->HasBombs(fx, fx.weapon))
|
||||
{
|
||||
fx.strategy = this.ExecuteRanged;
|
||||
fx.projectile_speed = 75;
|
||||
fx.aim_wait = 85;
|
||||
fx.ammo_check = this.HasBombs;
|
||||
fx.ranged = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
fx.weapon = nil;
|
||||
}
|
||||
}
|
||||
|
||||
private func FindInventoryWeaponBlunderbuss(effect fx)
|
||||
{
|
||||
if (fx.weapon = fx.Target->FindContents(Blunderbuss))
|
||||
{
|
||||
if (this->HasAmmo(fx, fx.weapon))
|
||||
{
|
||||
fx.strategy = this.ExecuteRanged;
|
||||
fx.projectile_speed = 200;
|
||||
fx.aim_wait = 85;
|
||||
fx.ammo_check = this.HasAmmo;
|
||||
fx.ranged = true;
|
||||
fx.ranged_direct = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
fx.weapon = nil;
|
||||
}
|
||||
}
|
||||
|
||||
private func FindInventoryWeaponBow(effect fx)
|
||||
{
|
||||
if (fx.weapon = fx.Target->FindContents(Bow))
|
||||
{
|
||||
if (this->HasArrows(fx, fx.weapon))
|
||||
{
|
||||
fx.strategy = this.ExecuteRanged;
|
||||
fx.projectile_speed = 100;
|
||||
fx.aim_wait = 0;
|
||||
fx.ammo_check = this.HasArrows;
|
||||
fx.ranged = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
fx.weapon = nil;
|
||||
}
|
||||
}
|
||||
|
||||
private func FindInventoryWeaponJavelin(effect fx)
|
||||
{
|
||||
if (fx.weapon = fx.Target->FindContents(Javelin))
|
||||
{
|
||||
fx.strategy = this.ExecuteRanged;
|
||||
fx.projectile_speed = fx.Target.ThrowSpeed * fx.weapon.shooting_strength / 100;
|
||||
fx.aim_wait = 16;
|
||||
fx.ranged=true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-- Editor Properties --*/
|
||||
|
||||
|
@ -580,13 +601,17 @@ public func Definition(proplist def)
|
|||
{
|
||||
if (!Clonk.EditorProps)
|
||||
Clonk.EditorProps = {};
|
||||
Clonk.EditorProps.AI =
|
||||
if (def == AI) // TODO: Make AI an enum so different AI types can be selected.
|
||||
{
|
||||
Type = "has_effect",
|
||||
Effect = "FxAI",
|
||||
Set = Format("%i->SetAI", def),
|
||||
SetGlobal = true
|
||||
};
|
||||
Clonk.EditorProps.AI =
|
||||
{
|
||||
Type = "has_effect",
|
||||
Effect = "FxAI",
|
||||
Set = Format("%i->SetAI", def),
|
||||
SetGlobal = true
|
||||
};
|
||||
}
|
||||
def->DefinitionAttackModes(def);
|
||||
// Add AI user actions.
|
||||
var enemy_evaluator = UserAction->GetObjectEvaluator("IsClonk", "$Enemy$", "$EnemyHelp$");
|
||||
enemy_evaluator.Priority = 100;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
Use ChangeEffect properly to save calls
|
||||
*/
|
||||
|
||||
local fade_time;
|
||||
local fade_time = 18;
|
||||
|
||||
protected func Activate(int plr)
|
||||
{
|
||||
|
@ -28,7 +28,6 @@ protected func Initialize()
|
|||
FindObject(Find_ID(Rule_ObjectFade), Find_Exclude(this))->DoFadeTime(36);
|
||||
return RemoveObject();
|
||||
}
|
||||
fade_time = 18; // 18, because the timer will check once per second, so it's aproximately a second.
|
||||
AddTimer("Timer");
|
||||
}
|
||||
|
||||
|
@ -55,6 +54,12 @@ public func FxIntFadeOutCandidateTimer(object target, effect, int time)
|
|||
return FX_OK;
|
||||
}
|
||||
|
||||
public func FadeOutObject(object target)
|
||||
{
|
||||
// Definition or hooked call: Fade out an object (even if rule is not active)
|
||||
return AddEffect("IntFadeOut", target, 100, 1, nil, Rule_ObjectFade);
|
||||
}
|
||||
|
||||
func CheckFadeConditions(object fade)
|
||||
{
|
||||
// Moving objects should not.
|
||||
|
|
|
@ -46,9 +46,23 @@ global func SaveScenarioObjects(f, duplicate_objects)
|
|||
// ...Except player crew
|
||||
var ignore_objs = [];
|
||||
if (!save_scenario_dup_objects)
|
||||
{
|
||||
for (var iplr = 0; iplr < GetPlayerCount(C4PT_User); ++iplr)
|
||||
{
|
||||
for (var icrew = 0, crew; crew = GetCrew(GetPlayerByIndex(iplr, C4PT_User), icrew); ++icrew)
|
||||
{
|
||||
ignore_objs[GetLength(ignore_objs)] = crew;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ignore objects tagged with a no-save effect
|
||||
for (obj in objs)
|
||||
{
|
||||
if (GetEffect("IntNoScenarioSave", obj))
|
||||
{
|
||||
ignore_objs[GetLength(ignore_objs)] = obj;
|
||||
}
|
||||
}
|
||||
// Write creation data and properties
|
||||
var obj_data = SaveScen_Objects(objs, ignore_objs, props_prototype);
|
||||
// Resolve dependencies
|
||||
|
@ -59,12 +73,14 @@ global func SaveScenarioObjects(f, duplicate_objects)
|
|||
FileWrite(f, "/* Automatically created objects file */\n\n");
|
||||
// Declare static variables for objects that wish to have them
|
||||
for (obj in objs)
|
||||
{
|
||||
if (obj.StaticSaveVar && !save_scenario_dup_objects)
|
||||
{
|
||||
if (!any_written) FileWrite(f, "static "); else FileWrite(f, ", ");
|
||||
FileWrite(f, obj.StaticSaveVar);
|
||||
any_written = true;
|
||||
}
|
||||
}
|
||||
if (any_written)
|
||||
{
|
||||
FileWrite(f, ";\n\n");
|
||||
|
|
Loading…
Reference in New Issue