Track Unity source, scenes, editable assets, licenses, tools and QA evidence. Exclude generated caches, Windows builds and raw runtime logs.
278 lines
13 KiB
C#
278 lines
13 KiB
C#
using UnityEngine;
|
|
|
|
namespace Ironspore
|
|
{
|
|
public sealed class WarzoneDirector : MonoBehaviour
|
|
{
|
|
public MechPilot Player
|
|
{
|
|
get; private set;
|
|
}
|
|
public WorldInteractable Focused
|
|
{
|
|
get; private set;
|
|
}
|
|
public float ExtractionRemaining { get; private set; } = -1;
|
|
public bool TransportReady
|
|
{
|
|
get; private set;
|
|
}
|
|
public EscortUnit Escort
|
|
{
|
|
get; private set;
|
|
}
|
|
Transform root;
|
|
GameSession game;
|
|
Vector3 extractionPosition = new Vector3(-19, 0, -8);
|
|
GameObject transport;
|
|
|
|
void ResetWorld()
|
|
{
|
|
game = GetComponent<GameSession>();
|
|
if (root)
|
|
{
|
|
root.gameObject.SetActive(false);
|
|
Destroy(root.gameObject);
|
|
}
|
|
root = new GameObject("World").transform;
|
|
ExtractionRemaining = -1;
|
|
TransportReady = false;
|
|
Focused = null;
|
|
Escort = null;
|
|
RenderSettings.ambientLight = new Color(.27f, .34f, .38f);
|
|
RenderSettings.fog = true;
|
|
RenderSettings.fogColor = new Color(.09f, .14f, .18f);
|
|
RenderSettings.fogDensity = .009f;
|
|
var sun = new GameObject("Sun");
|
|
sun.transform.SetParent(root);
|
|
sun.transform.rotation = Quaternion.Euler(48, -35, 0);
|
|
var light = sun.AddComponent<Light>();
|
|
light.type = LightType.Directional;
|
|
light.intensity = 1.7f;
|
|
light.color = new Color(1, .87f, .72f);
|
|
light.shadows = LightShadows.Soft;
|
|
WorldFactory.Box("Ground", new Vector3(0, -.3f, 8), new Vector3(72, .6f, 100), new Color(.11f, .16f, .18f), root);
|
|
for (int x = -30; x <= 30; x += 5)
|
|
WorldFactory.Box("FloorSeam", new Vector3(x, .008f, 8), new Vector3(.035f, .015f, 96), new Color(.18f, .24f, .26f), root, false);
|
|
for (int z = -35; z <= 50; z += 5)
|
|
WorldFactory.Box("FloorSeam", new Vector3(0, .009f, z), new Vector3(68, .016f, .035f), new Color(.18f, .24f, .26f), root, false);
|
|
for (int side = -1; side <= 1; side += 2)
|
|
{
|
|
WorldFactory.Box("Boundary", new Vector3(side * 35, 2, 10), new Vector3(1, 4, 96), new Color(.15f, .22f, .25f), root);
|
|
for (int z = -25; z < 50; z += 12)
|
|
{
|
|
WorldFactory.Box("Pillar", new Vector3(side * 30, 5, z), new Vector3(1.5f, 10, 1.5f), new Color(.19f, .27f, .29f), root);
|
|
WorldFactory.Box("AmberStripe", new Vector3(side * 29.2f, 3, z), new Vector3(.07f, .25f, 1.7f), new Color(1, .57f, .18f), root, false, true);
|
|
}
|
|
}
|
|
}
|
|
public void BuildHangar()
|
|
{
|
|
ResetWorld();
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
var model = Instantiate(game.mechModel, root);
|
|
model.name = "HangarChassis_" + i;
|
|
model.transform.position = new Vector3(i * 4 - 2, 0, 2);
|
|
model.transform.localScale = game.chassis[i].modelScale;
|
|
model.transform.rotation = Quaternion.AngleAxis(180, Vector3.up) * model.transform.rotation;
|
|
WorldFactory.Cylinder("DisplayPad", new Vector3(i * 4 - 2, .05f, 2), new Vector3(3, .1f, 3), game.chassis[i].accent, root, false);
|
|
}
|
|
var camera = new GameObject("HangarCamera");
|
|
camera.transform.SetParent(root);
|
|
camera.AddComponent<Camera>().fieldOfView = 47;
|
|
camera.transform.position = new Vector3(11, 4.3f, -11);
|
|
camera.transform.LookAt(new Vector3(2, 1.5f, 2));
|
|
camera.AddComponent<AudioListener>();
|
|
WorldFactory.Box("RoofBeam", new Vector3(0, 9, 4), new Vector3(62, 1.3f, 2), new Color(.16f, .22f, .24f), root);
|
|
}
|
|
public void BuildWarzone()
|
|
{
|
|
ResetWorld();
|
|
var run = game.Run;
|
|
var avatar = new GameObject("PlayerMech");
|
|
avatar.transform.SetParent(root);
|
|
avatar.transform.position = new Vector3(0, .1f, -18);
|
|
Player = avatar.AddComponent<MechPilot>();
|
|
Player.Initialize(game, game.mechModel);
|
|
var random = new System.Random(run.seed + run.stage * 7919);
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
float x = (i % 2 == 0 ? -1 : 1) * (8 + (i % 3) * 5);
|
|
float z = -10 + i * 6;
|
|
var color = i % 2 == 0 ? new Color(.22f, .34f, .37f) : new Color(.45f, .26f, .15f);
|
|
WorldFactory.Box("FreightContainer", new Vector3(x, 1.1f, z), new Vector3(5.5f, 2.2f, 3), color, root);
|
|
for (int rib = 0; rib < 5; rib++)
|
|
WorldFactory.Box("ContainerRib", new Vector3(x - 2 + rib, 1.1f, z - 1.54f), new Vector3(.09f, 2.1f, .08f), new Color(.11f, .17f, .19f), root, false);
|
|
}
|
|
WorldFactory.Box("HighWalkway", new Vector3(19, 4, 14), new Vector3(6, .6f, 28), new Color(.23f, .3f, .3f), root);
|
|
var ramp = WorldFactory.Box("AccessRamp", new Vector3(19, 2, -6), new Vector3(6, .5f, 13), new Color(.3f, .34f, .31f), root);
|
|
ramp.transform.rotation = Quaternion.Euler(-18, 0, 0);
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
Vector3 pos = new Vector3(i % 2 == 0 ? -8 : 9, 0, -6 + i * 6);
|
|
string key = "zone" + run.stage + "_crate" + i;
|
|
if (run.searched.Contains(key))
|
|
continue;
|
|
string item = i == 0 ? "blueprint_boost_efficient" : i == 3 ? "blueprint_coil_capacitor" : i == 5 ? "blueprint_reactive_guard" : (i + run.biome) % 2 == 0 ? "alloy" : "cells";
|
|
var crate = WorldFactory.Box("SalvageCrate", pos + Vector3.up * .65f, new Vector3(1.8f, 1.3f, 1.4f), new Color(.24f, .42f, .39f), root);
|
|
WorldFactory.Box("CrateLatch", pos + new Vector3(0, 1.32f, 0), new Vector3(1.4f, .08f, .85f), new Color(.15f, .95f, .73f), root, false, true);
|
|
var interaction = crate.AddComponent<WorldInteractable>();
|
|
interaction.kind = 0;
|
|
interaction.key = key;
|
|
interaction.itemId = item;
|
|
interaction.amount = item.StartsWith("blueprint_") ? 1 : random.Next(2, 6);
|
|
interaction.offersPart = i == 2 || i == 4;
|
|
interaction.partSlot = i == 2 ? 2 : 0;
|
|
interaction.partIndex = run.stage % 2 == 0 ? 1 : 2;
|
|
interaction.RefreshLabel();
|
|
}
|
|
var objective = WorldFactory.Box("NavigationRelay", new Vector3(0, 1.5f, 23), new Vector3(2.2f, 3, 1.6f), new Color(.21f, .33f, .36f), root);
|
|
WorldFactory.Box("RelayScreen", new Vector3(0, 2.4f, 22.14f), new Vector3(1.5f, .65f, .1f), new Color(.1f, .9f, .83f), root, false, true);
|
|
var objectiveAction = objective.AddComponent<WorldInteractable>();
|
|
objectiveAction.kind = 1;
|
|
objectiveAction.RefreshLabel();
|
|
var onward = WorldFactory.Cylinder("OnwardGate", new Vector3(0, .05f, 36), new Vector3(7, .1f, 7), new Color(.3f, .6f, .65f), root, false);
|
|
var onwardAction = onward.AddComponent<WorldInteractable>();
|
|
onwardAction.kind = 2;
|
|
onwardAction.RefreshLabel();
|
|
WorldFactory.Cylinder("ExtractionPad", extractionPosition + Vector3.up * .06f, new Vector3(7, .12f, 7), new Color(.85f, .47f, .14f), root, false);
|
|
for (int i = 0; i < 4; i++)
|
|
WorldFactory.Box("LandingLight", extractionPosition + new Vector3(i % 2 == 0 ? -3 : 3, .25f, i < 2 ? -3 : 3), new Vector3(.3f, .5f, .3f), new Color(1, .65f, .2f), root, false, true);
|
|
var pad = new GameObject("ExtractionBeacon");
|
|
pad.transform.SetParent(root);
|
|
pad.transform.position = extractionPosition;
|
|
var evac = pad.AddComponent<WorldInteractable>();
|
|
evac.kind = 3;
|
|
evac.RefreshLabel();
|
|
WorldFactory.Label("world.extraction", extractionPosition + Vector3.up * 3, new Color(1, .7f, .3f), root);
|
|
WorldFactory.Label("world.relay", new Vector3(0, 5, 23), new Color(.25f, 1, .85f), root);
|
|
int count = game.Trial ? 2 : 3 + run.stage;
|
|
for (int i = 0; i < count; i++)
|
|
SpawnEnemy(new Vector3((i % 2 == 0 ? -1 : 1) * (4 + i % 3 * 3), .1f, 6 + i * 5), i % 3, i);
|
|
if (!game.Trial && run.stage == 4)
|
|
{
|
|
objective.SetActive(false);
|
|
if (run.branch == 0 && !run.routeCompleted)
|
|
SpawnEnemy(new Vector3(0, .1f, 29), 3, 99);
|
|
if (run.branch == 1 && !run.routeCompleted)
|
|
{
|
|
var cart = WorldFactory.Box("EscortEngineer", new Vector3(0, 1.3f, 0), new Vector3(3, 2.6f, 4), new Color(.2f, .55f, .5f), root);
|
|
Escort = cart.AddComponent<EscortUnit>();
|
|
Escort.Initialize(game);
|
|
}
|
|
}
|
|
}
|
|
void SpawnEnemy(Vector3 pos, int type, int number)
|
|
{
|
|
var obj = new GameObject("Enemy_" + number);
|
|
obj.transform.SetParent(root);
|
|
obj.transform.position = pos;
|
|
obj.layer = 9;
|
|
obj.AddComponent<EnemyUnit>().Initialize(game, type, game.mechModel, root);
|
|
}
|
|
public void CallExtraction()
|
|
{
|
|
if (TransportReady)
|
|
{
|
|
game.EndSortie(false);
|
|
return;
|
|
}
|
|
if (ExtractionRemaining >= 0)
|
|
{
|
|
game.Notify("notice.transportInbound");
|
|
return;
|
|
}
|
|
ExtractionRemaining = 15;
|
|
game.Notify("notice.extractionCalled");
|
|
GameAudio.Cue(410, .2f);
|
|
}
|
|
void Update()
|
|
{
|
|
if (!game || !game.InField || game.Paused || !Player)
|
|
return;
|
|
if (ExtractionRemaining >= 0 && !TransportReady)
|
|
{
|
|
ExtractionRemaining = Mathf.Max(0, ExtractionRemaining - Time.deltaTime);
|
|
if (ExtractionRemaining == 0)
|
|
{
|
|
TransportReady = true;
|
|
transport = WorldFactory.Box("RecoveryTransport", extractionPosition + new Vector3(0, 5.5f, 0), new Vector3(7, 1.8f, 10), new Color(.24f, .3f, .32f), root, false);
|
|
WorldFactory.Box("TransportWing", transport.transform.position, new Vector3(14, .5f, 3), new Color(.32f, .4f, .41f), root, false);
|
|
game.Notify("notice.transportReady");
|
|
GameAudio.Cue(950, .3f);
|
|
}
|
|
}
|
|
Focused = null;
|
|
float nearest = 4.5f;
|
|
foreach (var interaction in root.GetComponentsInChildren<WorldInteractable>())
|
|
{
|
|
if (interaction.collected)
|
|
continue;
|
|
float distance = Vector3.Distance(Player.transform.position, interaction.transform.position);
|
|
if (distance < nearest)
|
|
{
|
|
nearest = distance;
|
|
Focused = interaction;
|
|
}
|
|
}
|
|
}
|
|
public void LaunchPod(Vector3 position)
|
|
{
|
|
var pod = WorldFactory.Box("CargoPod", position + Vector3.up * 2, new Vector3(1.4f, 1, 1.4f), new Color(.1f, .8f, .6f), root, false, true);
|
|
pod.AddComponent<PodFlight>();
|
|
}
|
|
}
|
|
|
|
public sealed class WorldInteractable : MonoBehaviour
|
|
{
|
|
public int kind;
|
|
public string key, itemId;
|
|
public int amount;
|
|
public bool collected, offersPart;
|
|
public int partSlot, partIndex;
|
|
public string Prompt
|
|
{
|
|
get
|
|
{
|
|
var g = GameSession.Active;
|
|
if (kind == 0)
|
|
return GameLocalization.Text("prompt.search");
|
|
if (kind == 1)
|
|
return GameLocalization.Text(g.Run.objectiveDone ? "prompt.relayOnline" : "prompt.objective");
|
|
if (kind == 2)
|
|
return GameLocalization.Text(g.Run.objectiveDone ? "prompt.route" : "prompt.routeLocked");
|
|
return GameLocalization.Text(g.World.TransportReady ? "prompt.board" : g.World.ExtractionRemaining >= 0 ? "prompt.inbound" : "prompt.call");
|
|
}
|
|
}
|
|
public void RefreshLabel()
|
|
{
|
|
if (collected)
|
|
transform.localScale = Vector3.one * .5f;
|
|
}
|
|
public void Activate()
|
|
{
|
|
var g = GameSession.Active;
|
|
if (kind == 0 && !collected)
|
|
g.Search(this);
|
|
else if (kind == 1)
|
|
g.CompleteObjective();
|
|
else if (kind == 2)
|
|
g.OpenRoutes();
|
|
else if (kind == 3)
|
|
g.World.CallExtraction();
|
|
}
|
|
}
|
|
public sealed class PodFlight : MonoBehaviour
|
|
{
|
|
float age;
|
|
void Update()
|
|
{
|
|
age += Time.deltaTime;
|
|
transform.position += Vector3.up * Time.deltaTime * (4 + age * 3);
|
|
if (age > 5)
|
|
Destroy(gameObject);
|
|
}
|
|
}
|
|
}
|