Add anger-scaled Sarka hunter waves every ten minutes
This commit is contained in:
@@ -55,7 +55,7 @@ modded class ERR_GameMode
|
||||
string enabled;
|
||||
if (SCR_Global.IsEditMode() || !Replication.IsServer() || !System.GetCLIParam("errBaseSmoke", enabled) || enabled != "1") return;
|
||||
string nativeEndCase;
|
||||
array<string> independentFixtures = {"coordinated-ai", "optional-site-skip", "infantry-combat", "medical-combat", "hunter-faction", "unconscious-camera", "self-epinephrine", "starter-backpack", "speech-download", "bundled-speech", "objective-map", "town-garrisons", "site-garrisons", "radio-interaction", "enemy-loadout", "aggression", "native-end-active", "native-end-preparing", "generated-sites", "roadblocks", "mortar-station", "opening-tools", "airfield-markers", "air-logistics", "air-assault", "air-recon"};
|
||||
array<string> independentFixtures = {"coordinated-ai", "optional-site-skip", "infantry-combat", "medical-combat", "hunter-faction", "unconscious-camera", "self-epinephrine", "starter-backpack", "speech-download", "bundled-speech", "objective-map", "town-garrisons", "site-garrisons", "radio-interaction", "enemy-loadout", "aggression", "sarka-hunters", "native-end-active", "native-end-preparing", "generated-sites", "roadblocks", "mortar-station", "opening-tools", "airfield-markers", "air-logistics", "air-assault", "air-recon"};
|
||||
if (System.GetCLIParam("errSmokeOutcome", nativeEndCase) && independentFixtures.Contains(nativeEndCase)) return;
|
||||
ERR_NativeObjectiveProbe.BeginRound();
|
||||
ERR_NativeProgressionIdentityProbe.BeginRound();
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
#ifdef WORKBENCH
|
||||
modded class ERR_HunterService
|
||||
{
|
||||
void ERR_ProbeSarkaDue(float now) { m_SarkaWaves.NextWave = now; }
|
||||
void ERR_ProbeSarkas(out array<ERR_HunterVehicle> cars)
|
||||
{
|
||||
cars.Clear();
|
||||
foreach (ERR_HunterVehicle unit : m_Hunters) if (unit.Sarka) cars.Insert(unit);
|
||||
}
|
||||
}
|
||||
modded class ERR_HQ
|
||||
{
|
||||
void ERR_ProbeSarkaBodies(float now)
|
||||
{
|
||||
for (int slot = 0; slot < 6; slot++)
|
||||
{
|
||||
ERR_HQReport report = new ERR_HQReport();
|
||||
report.TravelMode = "body"; report.MessageId = 200000 + slot;
|
||||
report.CasualtySourceId = "fixture-sarka-bodies"; report.CasualtyStrength = 6; report.CasualtySlot = slot;
|
||||
report.ObservedAt = now; report.Position = "5000 50 5000";
|
||||
Accept(report, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
modded class ERR_GameMode
|
||||
{
|
||||
protected int m_ERRSarkaStage;
|
||||
protected int m_ERRSarkaDeadline;
|
||||
protected bool m_ERRSarkaOrder;
|
||||
protected override void EOnInit(IEntity owner)
|
||||
{
|
||||
super.EOnInit(owner);
|
||||
string outcome;
|
||||
if (!Replication.IsServer() || SCR_Global.IsEditMode() || !System.GetCLIParam("errSmokeOutcome", outcome) || outcome != "sarka-hunters") return;
|
||||
m_ERRSarkaDeadline = System.GetTickCount() + 420000;
|
||||
GetGame().GetCallqueue().CallLater(ERR_SarkaProbeTick, 1000, true);
|
||||
}
|
||||
protected bool ERR_SarkaProbeCheck(bool ok, string detail)
|
||||
{
|
||||
if (ok) { Print("ERR SMOKE PASS: sarka " + detail); return true; }
|
||||
Print("ERR SMOKE FAIL: sarka " + detail, LogLevel.ERROR);
|
||||
GetGame().GetCallqueue().Remove(ERR_SarkaProbeTick); return false;
|
||||
}
|
||||
protected void ERR_SarkaProbeTick()
|
||||
{
|
||||
if (System.GetTickCount() >= m_ERRSarkaDeadline || Phase() == ERR_Phase.DEFEAT) { ERR_SarkaProbeCheck(false, "native spawn/admission/driving deadline"); return; }
|
||||
if (Phase() < ERR_Phase.PRISON || !GetGame().GetPlayerController()) return;
|
||||
IEntity player = GetGame().GetPlayerController().GetControlledEntity(); if (!player) return;
|
||||
DamageManagerComponent damage = DamageManagerComponent.Cast(player.FindComponent(DamageManagerComponent));
|
||||
if (damage) damage.EnableDamageHandling(false);
|
||||
ERR_HQ hq = ERR_HQ.Get(); if (!hq) return;
|
||||
float now = GetWorld().GetWorldTime();
|
||||
if (m_ERRSarkaStage == 0)
|
||||
{
|
||||
if (!ERR_SarkaProbeCheck(UnlockPrison(player) || Phase() >= ERR_Phase.RADIO_SEARCH, "prison released")) return;
|
||||
hq.ERR_ProbeSarkaBodies(now);
|
||||
if (!ERR_SarkaProbeCheck(hq.Watch().Aggression() == 2, "six delivered bodies produce two anger points")) return;
|
||||
// Accelerate only the opt-in wave deadline; production placement/admission run unchanged.
|
||||
hq.Hunters().ERR_ProbeSarkaDue(now); m_ERRSarkaStage = 1;
|
||||
}
|
||||
array<ERR_HunterVehicle> cars = {}; hq.Hunters().ERR_ProbeSarkas(cars);
|
||||
if (cars.Count() < 2) return;
|
||||
if (m_ERRSarkaStage == 1)
|
||||
{
|
||||
if (!ERR_SarkaProbeCheck(cars.Count() == 2, "two physical cars for two anger points")) return;
|
||||
array<vector> positions = {player.GetOrigin()};
|
||||
foreach (ERR_HunterVehicle car : cars)
|
||||
{
|
||||
if (!car.Registered) return;
|
||||
if (!ERR_SarkaProbeCheck(car.Entity.GetPrefabData().GetPrefabName() == ERR_SarkaRules.Prefab() && car.CrewValid(this) && car.Members.Count() == 4 && car.Seats.Count() == 4, "native S105 with four original seated crew")) return;
|
||||
if (!ERR_SarkaProbeCheck(ERR_SarkaRules.InBand(car.PatrolHome, positions), "actual road spawn 1-1.25 km from player")) return;
|
||||
if (!ERR_SarkaProbeCheck(hq.Hunters().VehicleRadioCapability(car.Driver) == 2 && car.Group.GetFaction() == EnemyFaction(), "physical vehicle manpack and selected hostile faction")) return;
|
||||
int medics;
|
||||
foreach (IEntity member : car.Members)
|
||||
{
|
||||
ResourceName profile = member.GetPrefabData().GetPrefabName();
|
||||
if (profile == ERR_EnemyMedicalCatalog.Crew(this, true)) medics++;
|
||||
else if (!ERR_SarkaProbeCheck(profile == ERR_EnemyMedicalCatalog.Crew(this, false), "selected special-forces profile")) return;
|
||||
SCR_AICombatComponent combat = SCR_AICombatComponent.Cast(member.FindComponent(SCR_AICombatComponent));
|
||||
if (!combat || combat.GetAISkill() != EAISkill.CYLON || !combat.ERR_EnhancedEnemy()) return;
|
||||
}
|
||||
if (!ERR_SarkaProbeCheck(medics == 1, "one medic within the four-person team")) return;
|
||||
}
|
||||
m_ERRSarkaStage = 2;
|
||||
}
|
||||
if (cars[0].Waypoint) m_ERRSarkaOrder = true;
|
||||
if (!m_ERRSarkaOrder || vector.DistanceXZ(cars[0].PatrolHome, cars[0].Entity.GetOrigin()) < 30) return;
|
||||
if (!ERR_SarkaProbeCheck(hq.Hunters().Deployed() <= hq.Watch().HunterTarget(), "cars do not spend ordinary hunter allowance")) return;
|
||||
ERR_SarkaProbeCheck(true, "native patrol order and over 30 metres driven; all crew enhanced");
|
||||
GetGame().GetCallqueue().Remove(ERR_SarkaProbeTick);
|
||||
Print("ERR SMOKE COMPLETE: sarka hunters, two anger points, two four-person SF cars, road distance, radio and driving");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -64,7 +64,7 @@ class ERR_ScenarioComponent : ScriptComponent
|
||||
#ifdef WORKBENCH
|
||||
string historicalFixture;
|
||||
if (!m_TerrainIndependent && System.GetCLIParam("errSmokeOutcome", historicalFixture) && historicalFixture != "normal-escape-route" && historicalFixture != "crash-start" && historicalFixture != "mounted-ammo" && historicalFixture != "alarm-hearing" && historicalFixture != "optional-site-skip" && historicalFixture != "infantry-combat" && historicalFixture != "site-garrisons" && historicalFixture != "generated-sites" && historicalFixture != "roadblocks" && historicalFixture != "opening-tools" && historicalFixture != "airfield-markers" && historicalFixture != "air-recon" && historicalFixture != "air-logistics" && historicalFixture != "air-assault")
|
||||
if (historicalFixture != "self-epinephrine" && historicalFixture != "starter-backpack" && historicalFixture != "objective-map" && historicalFixture != "speech-download" && historicalFixture != "bundled-speech") m_Definition = "{ACA98B44E2173605}Configs/ERR/Tests/LegacySites.conf";
|
||||
if (historicalFixture != "sarka-hunters" && historicalFixture != "self-epinephrine" && historicalFixture != "starter-backpack" && historicalFixture != "objective-map" && historicalFixture != "speech-download" && historicalFixture != "bundled-speech") m_Definition = "{ACA98B44E2173605}Configs/ERR/Tests/LegacySites.conf";
|
||||
#endif
|
||||
m_RuntimeDefinition = ERR_ScenarioDefinition.Cast(SCR_BaseContainerTools.CreateInstanceFromPrefab(m_Definition));
|
||||
if (!m_RuntimeDefinition || !m_RuntimeDefinition.Valid()) { m_Failed = true; return ERR_PrepareResult.FAILED; }
|
||||
@@ -72,7 +72,7 @@ class ERR_ScenarioComponent : ScriptComponent
|
||||
// Existing deterministic probes intentionally use authored coordinates.
|
||||
string fixture;
|
||||
if (!m_TerrainIndependent && System.GetCLIParam("errSmokeOutcome", fixture) && fixture != "normal-escape-route" && fixture != "crash-start" && fixture != "mounted-ammo" && fixture != "alarm-hearing" && fixture != "optional-site-skip" && fixture != "infantry-combat" && fixture != "site-garrisons" && fixture != "generated-sites" && fixture != "roadblocks" && fixture != "airfield-markers" && fixture != "air-recon" && fixture != "air-logistics" && fixture != "air-assault")
|
||||
if (fixture != "self-epinephrine" && fixture != "starter-backpack" && fixture != "objective-map" && fixture != "speech-download" && fixture != "bundled-speech") foreach (ERR_SiteDefinition fixedSite : m_RuntimeDefinition.Sites) fixedSite.RandomClear = false;
|
||||
if (fixture != "sarka-hunters" && fixture != "self-epinephrine" && fixture != "starter-backpack" && fixture != "objective-map" && fixture != "speech-download" && fixture != "bundled-speech") foreach (ERR_SiteDefinition fixedSite : m_RuntimeDefinition.Sites) fixedSite.RandomClear = false;
|
||||
if (!ERR_ConfigurePatrolHQFixture(fixture)) { m_Failed = true; return ERR_PrepareResult.FAILED; }
|
||||
#endif
|
||||
if (m_Progressive && !m_RuntimeDefinition.ConfigurePopulation(m_Definition, mode.Settings().Get("fieldCampCount"), mode.Settings().Get("fieldHospitalCount")))
|
||||
|
||||
@@ -1741,6 +1741,7 @@ class ERR_HQ : ERR_CommandService
|
||||
|
||||
override void Maintain(float now)
|
||||
{
|
||||
m_Hunters.PauseSarkaIfEmpty();
|
||||
// Aircraft already airborne keep flying even when the server is empty.
|
||||
m_Recon.Tick(now);
|
||||
m_PlaneRecon.Tick(now);
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// Wave size is sampled from delivered body-driven aggression every ten minutes.
|
||||
// Failed placements remain pending in this wave, never accumulate into a backlog.
|
||||
class ERR_SarkaWaves
|
||||
{
|
||||
float NextWave = -1;
|
||||
float NextAttempt;
|
||||
int Pending;
|
||||
int Target;
|
||||
int Wave;
|
||||
int Spawned;
|
||||
void Pause() { NextWave = -1; Pending = 0; Target = 0; }
|
||||
bool Due(float now, int aggression, bool playing)
|
||||
{
|
||||
if (!playing) { Pause(); return false; }
|
||||
if (NextWave < 0) { NextWave = now + 600000; return false; }
|
||||
if (now >= NextWave)
|
||||
{
|
||||
NextWave = now + 600000; NextAttempt = now;
|
||||
Target = Math.Clamp(aggression, 0, 30); Pending = Target; Wave++;
|
||||
}
|
||||
if (Pending == 0 || now < NextAttempt) return false;
|
||||
NextAttempt = now + 5000;
|
||||
return true;
|
||||
}
|
||||
void Commit() { if (Pending > 0) { Pending--; Spawned++; } }
|
||||
}
|
||||
|
||||
class ERR_SarkaRules
|
||||
{
|
||||
static ResourceName Prefab() { return "{AD80FB47D868C775}Prefabs/Vehicles/Wheeled/S105/S105_green.et"; }
|
||||
static bool Seats(int drivers, int turrets, int cargo, int total)
|
||||
{
|
||||
return drivers == 1 && turrets == 0 && cargo == 3 && total == 4;
|
||||
}
|
||||
static bool InBand(vector position, array<vector> players)
|
||||
{
|
||||
if (players.IsEmpty() || !ERR_ForceRules.FiniteVector(position)) return false;
|
||||
float nearest = 1000000;
|
||||
foreach (vector player : players)
|
||||
{
|
||||
if (!ERR_ForceRules.FiniteVector(player)) return false;
|
||||
nearest = Math.Min(nearest, vector.DistanceXZ(position, player));
|
||||
}
|
||||
return nearest >= 1000 && nearest <= 1250;
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,7 @@ class ERR_HunterVehicle : ERR_ConvoyVehicle
|
||||
float PendingObservedAt = -1;
|
||||
bool TroopTransport;
|
||||
bool Motorbike;
|
||||
bool Sarka;
|
||||
bool OpeningPatrol;
|
||||
vector PatrolHome;
|
||||
bool RadioRequested;
|
||||
@@ -136,6 +137,87 @@ class ERR_HunterService : ERR_ConvoyService
|
||||
protected int m_ReserveSpent;
|
||||
protected float m_NextReserve;
|
||||
protected ref ERR_HunterVehicle m_PendingReserve;
|
||||
protected ref ERR_SarkaWaves m_SarkaWaves = new ERR_SarkaWaves();
|
||||
protected string m_SarkaStatus = "first wave ten minutes after prison escape";
|
||||
string SarkaStatus()
|
||||
{
|
||||
return string.Format(" Sarka waves: %1 deployed, %2/%3 pending in wave %4; %5.", m_SarkaWaves.Spawned, m_SarkaWaves.Pending, m_SarkaWaves.Target, m_SarkaWaves.Wave, m_SarkaStatus);
|
||||
}
|
||||
// HQ maintenance runs even while tactical ticks pause in an empty round.
|
||||
void PauseSarkaIfEmpty()
|
||||
{
|
||||
if (m_Stopped || !m_Mode || !m_Mode.Active()) return;
|
||||
array<IEntity> players = {}; ERR_Actors.Players(players);
|
||||
if (players.IsEmpty()) m_SarkaWaves.Pause();
|
||||
}
|
||||
protected void TickSarka(ERR_HQ hq, float now)
|
||||
{
|
||||
// Released crews keep their physical/HQ ownership; discard only wave tracking.
|
||||
for (int retired = m_Hunters.Count() - 1; retired >= 0; retired--)
|
||||
if (m_Hunters[retired].Sarka && m_Hunters[retired].Released) m_Hunters.Remove(retired);
|
||||
array<IEntity> players = {}; ERR_Actors.Players(players);
|
||||
int previousWave = m_SarkaWaves.Wave;
|
||||
bool due = m_SarkaWaves.Due(now, hq.Watch().Aggression(), !players.IsEmpty());
|
||||
if (previousWave != m_SarkaWaves.Wave)
|
||||
{
|
||||
m_SarkaStatus = "placing four-person special-forces teams on roads";
|
||||
if (m_SarkaWaves.Target == 0) m_SarkaStatus = "no aggression; next wave check in ten minutes";
|
||||
ERR_HQ.Event("SARKA WAVE", string.Format("wave=%1 aggression=%2 cars=%3 identified bodies=%4", m_SarkaWaves.Wave, hq.Watch().Aggression(), m_SarkaWaves.Target, hq.Watch().IdentifiedBodies()));
|
||||
}
|
||||
if (!due) return;
|
||||
int awaiting;
|
||||
foreach (ERR_HunterVehicle pending : m_Hunters) if (!pending.Released && !pending.Registered) awaiting++;
|
||||
if (m_Mode.Forces().Count() + awaiting >= 250) { m_SarkaStatus = "waiting for formation budget"; return; }
|
||||
if (!ERR_EnemyLoadoutCatalog.Available(ERR_EnemyMedicalCatalog.Crew(m_Mode, false)) || !ERR_EnemyLoadoutCatalog.Available(ERR_EnemyMedicalCatalog.Crew(m_Mode, true)))
|
||||
{ m_SarkaStatus = "selected faction lacks response crew"; return; }
|
||||
array<vector> positions = {};
|
||||
foreach (IEntity player : players) positions.Insert(player.GetOrigin());
|
||||
ERR_ConvoyPlacement placement = new ERR_ConvoyPlacement();
|
||||
for (int attempt = 0; attempt < 8; attempt++)
|
||||
{
|
||||
vector offset = Vector(Math.RandomFloat(-1, 1), 0, Math.RandomFloat(-1, 1));
|
||||
if (offset.Length() < 0.1) continue;
|
||||
vector seed = positions[Math.RandomInt(0, positions.Count())] + offset.Normalized() * 1125;
|
||||
vector position, angles;
|
||||
if (!ERR_SupplyConvoySystem.ApproachDirected(seed, position, angles, 150) || !ERR_SarkaRules.InBand(position, positions) || !placement.Clear(position, angles[0])) continue;
|
||||
bool occupied;
|
||||
foreach (ERR_HunterVehicle other : m_Hunters)
|
||||
if (other.Entity && vector.DistanceXZ(position, other.Entity.GetOrigin()) < 60) occupied = true;
|
||||
if (occupied) continue;
|
||||
if (SpawnSarka(now, position, angles))
|
||||
{
|
||||
m_SarkaWaves.Commit();
|
||||
m_SarkaStatus = "four-person teams join HQ hunters; departures spaced five seconds apart";
|
||||
}
|
||||
else m_SarkaStatus = "vehicle or crew setup failed; retrying this wave";
|
||||
return;
|
||||
}
|
||||
m_SarkaStatus = "waiting for a clear road 1-1.25 km from the nearest player";
|
||||
}
|
||||
protected bool SpawnSarka(float now, vector position, vector angles)
|
||||
{
|
||||
ERR_HunterVehicle unit = new ERR_HunterVehicle();
|
||||
unit.Sarka = true; unit.TroopTransport = true; unit.OpeningPatrol = true; unit.PatrolHome = position;
|
||||
unit.Source = "aggression-sarka-" + (m_SarkaWaves.Spawned + 1).ToString();
|
||||
IEntity spawned = ERR_Actors.Spawn(ERR_SarkaRules.Prefab(), position, angles);
|
||||
unit.Entity = Vehicle.Cast(spawned);
|
||||
if (!unit.Entity || !unit.Entity.FindComponent(AICarMovementComponent) || !unit.Entity.FindComponent(SCR_AIVehicleUsageComponent))
|
||||
{ ERR_Actors.DeleteSpawned(spawned); return false; }
|
||||
unit.Group = SCR_AIGroup.Cast(ERR_Actors.Spawn(ERR_ConvoyResources.GroupPrefab(), position));
|
||||
if (!unit.Group || !ERR_ConvoyRules.EmptyCrewTemplate(unit.Group) || !FillCrew(unit))
|
||||
{
|
||||
foreach (IEntity failed : unit.Members) ERR_Actors.DeleteSpawned(failed);
|
||||
ERR_Actors.DeleteSpawned(unit.Group); ERR_Actors.DeleteSpawned(unit.Entity); return false;
|
||||
}
|
||||
m_Mode.Own(unit.Entity); m_Mode.Own(unit.Group);
|
||||
ERR_Actors.SetFaction(unit.Entity, m_Mode.EnemyFaction());
|
||||
unit.LaunchedAt = now; unit.Deadline = now + 120000; m_Hunters.Insert(unit);
|
||||
unit.Recovery = new ERR_HunterCrewRecovery(unit); unit.Recovery.Update(m_Mode, now);
|
||||
AICarMovementComponent movement = AICarMovementComponent.Cast(unit.Entity.FindComponent(AICarMovementComponent));
|
||||
movement.SetCruiseSpeed(45);
|
||||
ERR_HQ.Event("SARKA SPAWN", string.Format("%1 wave=%2 crew=%3 position=%4; four original response soldiers including driver and medic", unit.Source, m_SarkaWaves.Wave, unit.Members.Count(), position));
|
||||
return true;
|
||||
}
|
||||
protected int m_OpeningDistance = 1000;
|
||||
// Called once when the round's HQ is created; menu edits affect the next HQ.
|
||||
void ConfigureOpening(int distance)
|
||||
@@ -275,7 +357,6 @@ class ERR_HunterService : ERR_ConvoyService
|
||||
if (!m_Mode.Active() || !actor || !entered || !m_Mode.Players()) return;
|
||||
ERR_HQ hq = ERR_HQ.Cast(m_Mode.Command());
|
||||
if (!hq || hq.Hunters() != this || !m_Mode.Players().CurrentActor(actor)) return;
|
||||
if (m_Hunters.Count() > 21) return;
|
||||
foreach (ERR_HunterVehicle unit : m_Hunters)
|
||||
{
|
||||
// Released survivors already have independent HQ ownership. Do not revoke
|
||||
@@ -304,7 +385,7 @@ class ERR_HunterService : ERR_ConvoyService
|
||||
int Deployed()
|
||||
{
|
||||
int count;
|
||||
foreach (ERR_HunterVehicle unit : m_Hunters) if (!unit.Motorbike) count++;
|
||||
foreach (ERR_HunterVehicle unit : m_Hunters) if (!unit.Motorbike && !unit.Sarka) count++;
|
||||
return count;
|
||||
}
|
||||
int ActiveHunters()
|
||||
@@ -324,7 +405,7 @@ class ERR_HunterService : ERR_ConvoyService
|
||||
{
|
||||
int count;
|
||||
foreach (ERR_HunterVehicle unit : m_Hunters)
|
||||
if (!unit.Motorbike && !ERR_HunterFleetRules.Unavailable(hq.Watch().Find(unit.Source), unit.LaunchedAt, now)) count++;
|
||||
if (!unit.Motorbike && !unit.Sarka && !ERR_HunterFleetRules.Unavailable(hq.Watch().Find(unit.Source), unit.LaunchedAt, now)) count++;
|
||||
return count;
|
||||
}
|
||||
protected ERR_HunterVehicle ReserveSource(ERR_HQ hq, float now)
|
||||
@@ -332,7 +413,7 @@ class ERR_HunterService : ERR_ConvoyService
|
||||
if (!ERR_HunterFleetRules.ReserveDue(Deployed(), m_Target, m_ReserveSpent, AvailableToHQ(hq, now), m_NextReserve, now)) return null;
|
||||
foreach (ERR_HunterVehicle unit : m_Hunters)
|
||||
{
|
||||
if (unit.Motorbike || unit.ReserveCovered || now - unit.LaunchedAt < 480000) continue;
|
||||
if (unit.Motorbike || unit.Sarka || unit.ReserveCovered || now - unit.LaunchedAt < 480000) continue;
|
||||
if (ERR_HunterFleetRules.Unavailable(hq.Watch().Find(unit.Source), unit.LaunchedAt, now)) return unit;
|
||||
}
|
||||
return null;
|
||||
@@ -344,7 +425,7 @@ class ERR_HunterService : ERR_ConvoyService
|
||||
ERR_HQ.Event("HUNTER RESERVE", string.Format("%1 replaces unavailable patrol %2; reserve=%3/3; next departure in at least 480s; silence is not a confirmed death", unit.Source, m_PendingReserve.Source, m_ReserveSpent));
|
||||
m_PendingReserve = null;
|
||||
}
|
||||
override string Status() { return string.Format("HQ hunting patrols: %1 active including bikes; %2 UAZ/trucks deployed; aggression allowance %3, reserve used %4/3 (15 total maximum). Reserve departures at least eight minutes apart. Motorbikes have a separate allowance.", ActiveHunters(), Deployed(), m_Target, m_ReserveSpent); }
|
||||
override string Status() { return string.Format("HQ hunting patrols: %1 active including bikes and Sarkas; %2 UAZ/trucks deployed; aggression allowance %3, reserve used %4/3 (15 total maximum). Reserve departures at least eight minutes apart. Motorbikes have a separate allowance.", ActiveHunters(), Deployed(), m_Target, m_ReserveSpent) + SarkaStatus(); }
|
||||
protected bool StartHunter(ERR_HQ hq, float now)
|
||||
{
|
||||
if ((!m_PendingReserve && Deployed() >= m_Target + m_ReserveSpent) || Deployed() >= 15 || m_Mode.Forces().Count() >= 250) return false;
|
||||
@@ -410,6 +491,10 @@ class ERR_HunterService : ERR_ConvoyService
|
||||
{
|
||||
if (!ERR_MotorbikeRules.Seats(drivers.Count(), turrets.Count(), cargo.Count(), all.Count())) return false;
|
||||
}
|
||||
else if (hunter.Sarka)
|
||||
{
|
||||
if (!ERR_SarkaRules.Seats(drivers.Count(), turrets.Count(), cargo.Count(), all.Count())) return false;
|
||||
}
|
||||
else if (!ERR_HunterFleetRules.Seats(hunter.TroopTransport, drivers.Count(), turrets.Count(), cargo.Count(), all.Count())) return false;
|
||||
unit.Seats.Insert(drivers[0]);
|
||||
foreach (BaseCompartmentSlot turret : turrets) unit.Seats.Insert(turret);
|
||||
@@ -653,6 +738,7 @@ class ERR_HunterService : ERR_ConvoyService
|
||||
}
|
||||
m_PendingReserve = null;
|
||||
TickMotorbikes(hq, now);
|
||||
TickSarka(hq, now);
|
||||
if (!m_Coordination) m_Coordination = new ERR_HunterCoordination(m_Mode);
|
||||
m_Coordination.Tick(hq, m_Hunters, now);
|
||||
foreach (ERR_HunterVehicle unit : m_Hunters)
|
||||
|
||||
Reference in New Issue
Block a user