Integrate physical radio calls and finite vehicle maintenance
This commit is contained in:
@@ -131,6 +131,7 @@ class ERR_EnemyEquipmentEntry
|
||||
|
||||
class ERR_EnemyEquipmentGroup
|
||||
{
|
||||
ref ERR_EnemyRadio Radio;
|
||||
SCR_AIGroup Group;
|
||||
int Scans;
|
||||
float ReadyAt;
|
||||
@@ -144,17 +145,23 @@ class ERR_EnemyEquipment
|
||||
protected float m_NextCheck;
|
||||
protected bool m_Stopped;
|
||||
void ERR_EnemyEquipment(ERR_GameMode mode) { m_Mode = mode; }
|
||||
void RegisterGroup(SCR_AIGroup group)
|
||||
void RegisterGroup(SCR_AIGroup group, int radioId = 0, bool fitRadios = true)
|
||||
{
|
||||
if (m_Stopped || !Replication.IsServer() || !group || m_Groups.Count() >= 128) return;
|
||||
foreach (ERR_EnemyEquipmentGroup existing : m_Groups) if (existing.Group == group) return;
|
||||
ERR_EnemyEquipmentGroup state = new ERR_EnemyEquipmentGroup(); state.Group = group;
|
||||
state.ReadyAt = GetGame().GetWorld().GetWorldTime() + 2000;
|
||||
if (fitRadios && radioId > 0) state.Radio = new ERR_EnemyRadio(group, radioId);
|
||||
m_Groups.Insert(state);
|
||||
}
|
||||
void UnregisterGroup(SCR_AIGroup group)
|
||||
{
|
||||
foreach (ERR_EnemyEquipmentGroup state : m_Groups) if (state.Group == group) state.Scans = 5;
|
||||
foreach (ERR_EnemyEquipmentGroup state : m_Groups)
|
||||
{
|
||||
if (state.Group != group) continue;
|
||||
state.Scans = 5;
|
||||
if (state.Radio) state.Radio.Stop();
|
||||
}
|
||||
foreach (ERR_EnemyEquipmentEntry entry : m_Entries) if (entry.Group == group) entry.Stop(m_Mode);
|
||||
}
|
||||
protected bool Known(IEntity actor)
|
||||
@@ -182,6 +189,7 @@ class ERR_EnemyEquipment
|
||||
entry.Combat = SCR_AICombatComponent.Cast(actor.FindComponent(SCR_AICombatComponent));
|
||||
if (entry.Combat) entry.Combat.ERR_BindEnemySkill(m_Mode, state.Group);
|
||||
m_Entries.Insert(entry);
|
||||
if (state.Radio) state.Radio.Register(actor);
|
||||
}
|
||||
}
|
||||
foreach (ERR_EnemyEquipmentEntry entry : m_Entries)
|
||||
@@ -198,12 +206,15 @@ class ERR_EnemyEquipment
|
||||
entry.Check(m_Mode);
|
||||
if (entry.Optics) entry.Optics.Check(m_Mode);
|
||||
}
|
||||
foreach (ERR_EnemyEquipmentGroup state : m_Groups)
|
||||
if (state.Radio && now >= state.ReadyAt) state.Radio.Check(m_Mode);
|
||||
}
|
||||
void Stop()
|
||||
{
|
||||
if (m_Stopped) return;
|
||||
m_Stopped = true;
|
||||
foreach (ERR_EnemyEquipmentEntry entry : m_Entries) entry.Stop(m_Mode);
|
||||
foreach (ERR_EnemyEquipmentGroup state : m_Groups) if (state.Radio) state.Radio.Stop();
|
||||
m_Groups.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
// Owner-authorized group startup radio fitting; provenance in equipment migration docs.
|
||||
// Existing HQ registration selects the group. Physical inventory alone enables routes.
|
||||
class ERR_EnemyRadio
|
||||
{
|
||||
static const ResourceName BASIC = "{E1A5D4B878AA8980}Prefabs/Items/Equipment/Radios/Radio_R148.et";
|
||||
static const ResourceName MANPACK = "{54C68E438DD34265}Prefabs/Items/Equipment/Radios/Radio_R107M.et";
|
||||
protected SCR_AIGroup m_Group;
|
||||
protected bool m_RelaySelected;
|
||||
protected bool m_BasicDone;
|
||||
protected bool m_RelayDone;
|
||||
protected bool m_Captured;
|
||||
protected bool m_Stopped;
|
||||
protected int m_Checks;
|
||||
protected int m_Requests;
|
||||
protected int m_Completed;
|
||||
protected ref array<IEntity> m_Members = {};
|
||||
protected ref array<IEntity> m_Allowed = {};
|
||||
protected ref array<IEntity> m_BasicAttempts = {};
|
||||
protected ref array<IEntity> m_RelayAttempts = {};
|
||||
protected IEntity m_PendingActor;
|
||||
protected int m_PendingType;
|
||||
protected bool m_Submitted;
|
||||
protected ref ERR_EnemyEquipmentCallback m_Operation;
|
||||
void ERR_EnemyRadio(SCR_AIGroup group, int radioId)
|
||||
{
|
||||
m_Group = group;
|
||||
m_RelaySelected = radioId > 0 && radioId % 4 == 1;
|
||||
m_RelayDone = !m_RelaySelected;
|
||||
if (radioId <= 0) m_Stopped = true;
|
||||
}
|
||||
// Only the equipment coordinator may add newly seen original actors. Its
|
||||
// retained actor tombstones exclude transferred bodies from another grant.
|
||||
void Register(IEntity actor)
|
||||
{
|
||||
if (m_Stopped || m_Captured || !actor || m_Allowed.Count() >= 32 || m_Allowed.Contains(actor)) return;
|
||||
m_Allowed.Insert(actor);
|
||||
}
|
||||
// Negative means inventory is not yet inspectable, never permission to issue.
|
||||
static int Capability(IEntity actor)
|
||||
{
|
||||
if (!actor) return -1;
|
||||
InventoryStorageManagerComponent inventory = InventoryStorageManagerComponent.Cast(actor.FindComponent(InventoryStorageManagerComponent));
|
||||
if (!inventory) return -1;
|
||||
array<IEntity> items = {}; inventory.GetItems(items);
|
||||
if (items.Count() > 256) return -1;
|
||||
int capability;
|
||||
foreach (IEntity item : items)
|
||||
{
|
||||
if (!item || !item.FindComponent(BaseRadioComponent)) continue;
|
||||
capability = 1;
|
||||
SCR_RadioComponent radio = SCR_RadioComponent.Cast(item.FindComponent(SCR_RadioComponent));
|
||||
if (radio && radio.ERR_IsHQManpack()) return 2;
|
||||
}
|
||||
return capability;
|
||||
}
|
||||
protected void Finish(string reason)
|
||||
{
|
||||
if (m_Stopped) return;
|
||||
m_Stopped = true;
|
||||
ERR_HQ.Event("RADIO EQUIPMENT", reason);
|
||||
}
|
||||
void Stop() { Finish("startup fitting stopped; accepted native insert is not cancelled or replaced"); }
|
||||
protected bool OriginalCrew(ERR_GameMode mode)
|
||||
{
|
||||
array<AIAgent> agents = {}; m_Group.GetAgents(agents);
|
||||
if (agents.IsEmpty() || agents.Count() > 32) return false;
|
||||
array<IEntity> current = {};
|
||||
foreach (AIAgent agent : agents)
|
||||
{
|
||||
if (!agent) return false;
|
||||
IEntity actor = agent.GetControlledEntity();
|
||||
if (!m_Allowed.Contains(actor) || !ERR_EnemyEquipmentRules.Eligible(mode, m_Group, actor) || current.Contains(actor)) return false;
|
||||
current.Insert(actor);
|
||||
}
|
||||
if (!m_Captured)
|
||||
{
|
||||
foreach (IEntity original : current) m_Members.Insert(original);
|
||||
m_Captured = true;
|
||||
}
|
||||
if (current.Count() != m_Members.Count()) return false;
|
||||
foreach (IEntity member : m_Members) if (!current.Contains(member)) return false;
|
||||
return true;
|
||||
}
|
||||
protected bool Submit(ERR_GameMode mode, int capability)
|
||||
{
|
||||
if (m_Stopped || m_Submitted) return false;
|
||||
ResourceName prefab = BASIC;
|
||||
if (capability == 2) prefab = MANPACK;
|
||||
foreach (IEntity actor : m_Members)
|
||||
{
|
||||
if (!ERR_EnemyEquipmentRules.Eligible(mode, m_Group, actor)) { Stop(); return false; }
|
||||
if (capability == 1 && m_BasicAttempts.Contains(actor)) continue;
|
||||
if (capability == 2 && m_RelayAttempts.Contains(actor)) continue;
|
||||
InventoryStorageManagerComponent inventory = InventoryStorageManagerComponent.Cast(actor.FindComponent(InventoryStorageManagerComponent));
|
||||
if (!inventory || !inventory.CanInsertResource(prefab, EStoragePurpose.PURPOSE_ANY)) continue;
|
||||
if (capability == 1) m_BasicAttempts.Insert(actor);
|
||||
else m_RelayAttempts.Insert(actor);
|
||||
m_PendingActor = actor; m_PendingType = capability;
|
||||
m_Operation = new ERR_EnemyEquipmentCallback(); m_Submitted = true; m_Requests++;
|
||||
bool accepted = inventory.TrySpawnPrefabToStorage(prefab, null, -1, EStoragePurpose.PURPOSE_ANY, m_Operation);
|
||||
if (!accepted && !(m_Operation.Finished && m_Operation.Succeeded)) m_Submitted = false;
|
||||
return true; // At most one native request across the entire group per check.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool Check(ERR_GameMode mode)
|
||||
{
|
||||
if (m_Stopped) return true;
|
||||
if (!Replication.IsServer() || SCR_Global.IsEditMode() || !mode || mode != ERR_GameMode.Get() || !mode.Active() || !m_Group || m_Group.IsSlave() || m_Group.GetPlayerCount(true) > 0 || m_Group.GetFaction() != mode.EnemyFaction()) { Stop(); return true; }
|
||||
m_Checks++;
|
||||
if (!m_Group.IsExpandComplete())
|
||||
{
|
||||
if (m_Checks >= 5) Finish("native startup crew did not complete before radio deadline");
|
||||
return m_Stopped;
|
||||
}
|
||||
if (!OriginalCrew(mode))
|
||||
{
|
||||
if (m_Captured || m_Checks >= 5) Finish("original radio crew unavailable or changed; no replacement");
|
||||
return m_Stopped;
|
||||
}
|
||||
bool known = true;
|
||||
int best;
|
||||
foreach (IEntity actor : m_Members)
|
||||
{
|
||||
int capability = Capability(actor);
|
||||
if (capability < 0) known = false;
|
||||
else if (capability > best) best = capability;
|
||||
}
|
||||
if (best >= 1) m_BasicDone = true;
|
||||
if (best >= 2) m_RelayDone = true;
|
||||
if (m_Submitted)
|
||||
{
|
||||
if (!ERR_EnemyEquipmentRules.Eligible(mode, m_Group, m_PendingActor)) { Stop(); return true; }
|
||||
if (m_Operation && m_Operation.Finished)
|
||||
{
|
||||
if (m_Operation.Succeeded)
|
||||
{
|
||||
m_Completed++; m_BasicDone = true;
|
||||
if (m_PendingType == 2) m_RelayDone = true;
|
||||
}
|
||||
m_Submitted = false;
|
||||
}
|
||||
}
|
||||
if (m_BasicDone && m_RelayDone)
|
||||
{
|
||||
if (m_Requests == 0) Finish("original group already equipped; no native radio request submitted");
|
||||
else if (m_Completed > 0) Finish("native radio completion recorded; original group allocation terminal, no replenishment");
|
||||
else Finish("physical group radio observed after request; insertion provenance unconfirmed, no replenishment");
|
||||
return true;
|
||||
}
|
||||
if (m_Checks >= 5)
|
||||
{
|
||||
if (m_Submitted) Finish("startup radio deadline; accepted unresolved insertion quarantined");
|
||||
else Finish("startup radio deadline; required compatible equipment not confirmed");
|
||||
return true;
|
||||
}
|
||||
if (m_Submitted || !known) return false;
|
||||
// A relay satisfies the basic need too; never submit both in parallel.
|
||||
if (!m_RelayDone && Submit(mode, 2)) return m_Stopped;
|
||||
if (!m_BasicDone) Submit(mode, 1);
|
||||
return m_Stopped;
|
||||
}
|
||||
}
|
||||
@@ -322,7 +322,7 @@ class ERR_HQ : ERR_CommandService
|
||||
int phase = unit.Id % 5;
|
||||
unit.NextReport = GetGame().GetWorld().GetWorldTime() + phase * 1000;
|
||||
m_Units.Insert(unit);
|
||||
m_Equipment.RegisterGroup(group);
|
||||
m_Equipment.RegisterGroup(group, unit.Id, !m_Mortars || !m_Mortars.FindGroup(group));
|
||||
BindPhysical(unit);
|
||||
unit.NextStatus = GetGame().GetWorld().GetWorldTime() + 10000 + phase * 1000;
|
||||
m_Journal.Write("REGISTER", string.Format("group %1", unit.Id));
|
||||
|
||||
@@ -13,7 +13,7 @@ class ERR_HQRadioNode
|
||||
bool Valid(bool manpack = false)
|
||||
{
|
||||
ERR_GameMode factions = ERR_GameMode.Get();
|
||||
if (!Carrier || !Group || Group.GetPlayerCount(true) > 0 || !factions || Group.GetFaction() != factions.EnemyFaction() || ERR_Actors.Group(Carrier) != Group)
|
||||
if (!ERR_Actors.CanFight(Carrier) || !Group || Group.GetPlayerCount(true) > 0 || !factions || Group.GetFaction() != factions.EnemyFaction() || ERR_Actors.Group(Carrier) != Group)
|
||||
return false;
|
||||
int required = 1;
|
||||
if (manpack)
|
||||
@@ -37,6 +37,8 @@ class ERR_HQRoute
|
||||
{
|
||||
ref array<ref ERR_HQRadioNode> Nodes = {};
|
||||
bool Downlink;
|
||||
bool Originated;
|
||||
float OriginDue = -1;
|
||||
int Cursor;
|
||||
bool Sending;
|
||||
float Due;
|
||||
@@ -59,6 +61,22 @@ class ERR_HQRoute
|
||||
}
|
||||
if (now - StartedAt > 30000)
|
||||
return Fail(journal, "route timed out");
|
||||
// An originating report needs three seconds on its original physical
|
||||
// caller before any network transmission. Later completed hops remain
|
||||
// independent of that caller, and HQ downlinks do not repeat this call.
|
||||
if (!Downlink && !Originated)
|
||||
{
|
||||
if (Nodes.IsEmpty() || !Nodes[0].Valid(Nodes.Count() == 1))
|
||||
return Fail(journal, "originating call lost its living owned radio carrier");
|
||||
if (OriginDue < 0)
|
||||
{
|
||||
OriginDue = now + 3000;
|
||||
journal.Write("CALL", Nodes[0].Label() + " originating report; three seconds before transmission", MessageId);
|
||||
}
|
||||
if (now < OriginDue) return 0;
|
||||
Originated = true;
|
||||
journal.Write("CALL COMPLETE", Nodes[0].Label() + " completed originating report", MessageId);
|
||||
}
|
||||
int target = Cursor + 1;
|
||||
if (Sending)
|
||||
{
|
||||
|
||||
@@ -188,6 +188,8 @@ class ERR_NativeHQMemoryProbe
|
||||
if (!m_Route) return 0;
|
||||
if (!Check(!hq.Memory().Get(m_Mode) && m_Route.Advance(now, hq.Journal()) == 0,
|
||||
"queued synthetic sighting has no belief while actual transmitter starts")) return -1;
|
||||
if (!Check(!m_Route.Originated && !m_Route.Sending && m_Route.OriginDue - m_Route.StartedAt == 3000,
|
||||
"uplink holds original caller for three seconds before its first network hop")) return -1;
|
||||
if (!Check(RemoveRadios(m_Route.Nodes[0].Carrier), "fixture removes actual transmitting equipment mid-uplink"))
|
||||
return -1;
|
||||
m_Step = 1; return 0;
|
||||
@@ -197,6 +199,7 @@ class ERR_NativeHQMemoryProbe
|
||||
if (hq.Memory().Get(m_Mode))
|
||||
{ Check(false, "interrupted uplink created a belief"); return -1; }
|
||||
if (!m_Route.Failed) return 0;
|
||||
if (!Check(!m_Route.Originated && !m_Route.Sending, "original caller radio loss interrupts call before any hop")) return -1;
|
||||
Print("ERR SMOKE PASS: HQ memory physical uplink loss prevents production Accept");
|
||||
m_Step = 2;
|
||||
}
|
||||
@@ -229,6 +232,7 @@ class ERR_NativeHQMemoryProbe
|
||||
if (m_Step == 3)
|
||||
{
|
||||
if (!current || current.MessageId != m_Report.MessageId) return 0;
|
||||
if (!Check(m_Route.Originated && now - m_Route.StartedAt >= 5000, "delivered uplink includes originating call and physical hop latency")) return -1;
|
||||
if (!Check(current.Position == m_Report.Position && current.SampleCount == 1,
|
||||
"actual uplink delivery reaches production intake exactly once")) return -1;
|
||||
m_BeliefId = current.BeliefId; m_Step = 4; return 0;
|
||||
|
||||
@@ -57,7 +57,7 @@ ERR_ScenarioDefinition {
|
||||
}
|
||||
ERR_SiteDefinition {
|
||||
Id "everon-supply-2"
|
||||
Label "Western supply cache"
|
||||
Label "Western supply cache (vehicle maintenance)"
|
||||
Kind 4
|
||||
Prefab "{7C3D16C17C24D351}Prefabs/ERR/SupplySite.et"
|
||||
Position 5960 0 7220
|
||||
@@ -80,6 +80,8 @@ ERR_ScenarioDefinition {
|
||||
MaximumTerrainRange 1
|
||||
}
|
||||
Stock {
|
||||
ERR_SiteStock { Prefab "{C09C7C97EFA34909}Prefabs/ERR/Items/EmergencyRepairKit.et" Count 1 }
|
||||
ERR_SiteStock { Prefab "{12D5AD21E383B768}Prefabs/Items/Fuel/Jerrycan_01/Jerrycan_01_item.et" Count 2 }
|
||||
ERR_SiteStock { Prefab "{FA5C25BF66A53DCF}Prefabs/Weapons/Rifles/AK74/Rifle_AK74.et" Count 4 }
|
||||
ERR_SiteStock { Prefab "{BBB50A815A2F916B}Prefabs/Weapons/Magazines/Magazine_545x39_AK_30rnd_Ball.et" Count 8 }
|
||||
ERR_SiteStock { Prefab "{C3F1FA1E2EC2B345}Prefabs/Items/Medicine/FieldDressing_01/FieldDressing_USSR_01.et" Count 6 }
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
GenericEntity : "{33B2DFDCD0EBA3DB}Prefabs/Items/Equipment/Kits/RepairKit_01/RepairKit_01_wrench.et" {
|
||||
components {
|
||||
InventoryItemComponent "{5222EB4D0C73006B}" {
|
||||
Attributes SCR_ItemAttributeCollection "{5222EB4D0A2B466B}" {
|
||||
ItemDisplayName SCR_InventoryUIInfo "{5222EB4D07D865FA}" {
|
||||
Name "Emergency repair kit"
|
||||
Description "Equip the wrench, approach a damaged vehicle part and use its repair action. Includes 20 finite supplies; vanilla emergency repair limits apply. Supplies do not regenerate."
|
||||
}
|
||||
}
|
||||
}
|
||||
SCR_ResourceComponent "{5E4A9574582A1D38}" {
|
||||
m_aContainers {
|
||||
SCR_ResourceContainer "{D42B6E62D20C2264}" {
|
||||
m_eResourceRights ALL
|
||||
m_eStorageType CARGO_PROP
|
||||
m_fResourceValueCurrent 20
|
||||
m_fResourceValueMax 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
MetaFileClass {
|
||||
Name "{C09C7C97EFA34909}Prefabs/ERR/Items/EmergencyRepairKit.et"
|
||||
Configurations {
|
||||
ResourceClass PC {
|
||||
}
|
||||
ResourceClass HEADLESS : PC {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,44 @@ class ERR_NativeTransportProbe
|
||||
radio.Transport = null;
|
||||
return Check(definition.Valid(), "valid authoring restored after isolated mutations");
|
||||
}
|
||||
// Read actual prepared stock only; this does not qualify repair/refuel use.
|
||||
protected bool MaintenanceStock()
|
||||
{
|
||||
if (!Check(m_Site && m_Site.Container && m_Mode.Sites().Owns(m_Site.Container), "maintenance cache has its original site-owned container")) return false;
|
||||
InventoryStorageManagerComponent inventory = InventoryStorageManagerComponent.Cast(m_Site.Container.FindComponent(InventoryStorageManagerComponent));
|
||||
if (!Check(inventory != null, "maintenance cache native inventory exists")) return false;
|
||||
array<IEntity> items = {}; ERR_Inventory.Items(inventory, items);
|
||||
if (!Check(items.Count() <= 128, "maintenance inventory enumeration remains bounded")) return false;
|
||||
int kits, cans;
|
||||
foreach (IEntity item : items)
|
||||
{
|
||||
if (!item || !item.GetPrefabData()) continue;
|
||||
ResourceName prefab = item.GetPrefabData().GetPrefabName();
|
||||
if (prefab == "{C09C7C97EFA34909}Prefabs/ERR/Items/EmergencyRepairKit.et")
|
||||
{
|
||||
kits++;
|
||||
SCR_ResourceComponent resource = SCR_ResourceComponent.Cast(item.FindComponent(SCR_ResourceComponent));
|
||||
SCR_ResourceContainer supplies;
|
||||
if (resource) supplies = resource.GetContainer(EResourceType.SUPPLIES);
|
||||
float amount = -1, capacity = -1;
|
||||
if (supplies) { amount = supplies.GetResourceValue(); capacity = supplies.GetMaxResourceValue(); }
|
||||
PrintFormat("ERR MAINTENANCE STOCK: repairKit=%1 owned=%2 supplies=%3 capacity=%4", item, m_Mode.Sites().Owns(item), amount, capacity);
|
||||
if (!Check(m_Mode.Sites().Owns(item) && supplies && Math.AbsFloat(amount - 20) <= 0.01
|
||||
&& Math.AbsFloat(capacity - 20) <= 0.01, "original repair kit contains twenty native supply units")) return false;
|
||||
}
|
||||
else if (prefab == "{12D5AD21E383B768}Prefabs/Items/Fuel/Jerrycan_01/Jerrycan_01_item.et")
|
||||
{
|
||||
cans++;
|
||||
SCR_FuelManagerComponent fuel = SCR_FuelManagerComponent.Cast(item.FindComponent(SCR_FuelManagerComponent));
|
||||
float litres = -1, maximum = -1;
|
||||
if (fuel) { litres = fuel.GetTotalFuel(); maximum = fuel.GetTotalMaxFuel(); }
|
||||
PrintFormat("ERR MAINTENANCE STOCK: fuelCan=%1 owned=%2 litres=%3 capacity=%4", item, m_Mode.Sites().Owns(item), litres, maximum);
|
||||
if (!Check(m_Mode.Sites().Owns(item) && fuel && Math.AbsFloat(litres - 5) <= 0.01
|
||||
&& Math.AbsFloat(maximum - 20) <= 0.01, "original fuel can contains five litres in its native twenty-litre tank")) return false;
|
||||
}
|
||||
}
|
||||
return Check(kits == 1 && cans == 2, "exactly one repair kit and two distinct original fuel cans are in the cache; consumption untested");
|
||||
}
|
||||
protected IEntity Character(int index)
|
||||
{
|
||||
IEntity actor = ERR_Actors.Spawn(m_Mode.Factions().PrisonerPrefab, ERR_Actors.Ground(m_Vehicle.GetOrigin() + Vector(-8 - index * 2, 0, 0)));
|
||||
@@ -84,6 +122,7 @@ class ERR_NativeTransportProbe
|
||||
if (!DefinitionChecks()) return -1;
|
||||
m_Site = m_Mode.Sites().Find("everon-supply-2");
|
||||
if (!Check(m_Site && m_Site.Transport && m_Mode.Sites().TransportCount() == 1 && m_Mode.Sites().Owns(m_Site.Transport), "exactly one authored transport belongs to the finite site service")) return -1;
|
||||
if (!MaintenanceStock()) return -1;
|
||||
m_Vehicle = m_Site.Transport;
|
||||
m_Controller = CarControllerComponent.Cast(m_Vehicle.FindComponent(CarControllerComponent));
|
||||
m_Fuel = SCR_FuelManagerComponent.Cast(m_Vehicle.FindComponent(SCR_FuelManagerComponent));
|
||||
|
||||
Reference in New Issue
Block a user