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; WorldLighting lighting; public TrainingCourse Course { get; private set; } Vector3 extractionPosition = new Vector3(-19, 0, -8); GameObject transport; void ResetWorld(bool hangar) { game = GetComponent(); if (root) { root.gameObject.SetActive(false); Destroy(root.gameObject); } root = new GameObject("World").transform; ExtractionRemaining = -1; TransportReady = false; Focused = null; Course = null; Escort = null; lighting = root.gameObject.AddComponent(); lighting.Initialize(game.lightingProfile, hangar); 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(true); 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.tag = "MainCamera"; camera.transform.SetParent(root); camera.AddComponent().fieldOfView = 47; camera.transform.position = new Vector3(11, 4.3f, -11); camera.transform.LookAt(new Vector3(2, 1.5f, 2)); camera.AddComponent(); WorldFactory.Box("RoofBeam", new Vector3(0, 9, 4), new Vector3(62, 1.3f, 2), new Color(.16f, .22f, .24f), root); lighting.CompleteEnvironment(camera.GetComponent(), true); } public void BuildWarzone() { ResetWorld(false); var run = game.Run; var avatar = new GameObject("PlayerMech"); avatar.transform.SetParent(root); avatar.transform.position = new Vector3(0, .1f, -18); Player = avatar.AddComponent(); 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); bool demo = game.Trial && (i == 1 || i == 2); if (demo) pos = new Vector3(-24, 0, i == 1 ? 9 : 18); 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); var interaction = crate.AddComponent(); 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.Build(root, pos, interaction.offersPart, demo); 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(); 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(); 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(); 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, (game.Trial ? 39 : 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(); Escort.Initialize(game); cart.layer = 10; } } if (game.Trial) { Course = root.gameObject.AddComponent(); Course.Build(game); } lighting.CompleteEnvironment(Player.GetComponentInChildren(), false); } 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().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); transport.layer = 10; WorldFactory.Box("TransportWing", transport.transform.position, new Vector3(14, .5f, 3), new Color(.32f, .4f, .41f), root, false).layer = 10; game.Notify("notice.transportReady"); GameAudio.Cue(950, .3f); } } Focused = null; float nearest = 4.5f; foreach (var interaction in root.GetComponentsInChildren()) { 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.layer = 10; pod.AddComponent(); } } public class WorldInteractable : MonoBehaviour { public int kind; public string key, itemId; public int amount; public bool collected, offersPart; public int partSlot, partIndex; public virtual 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 virtual void RefreshLabel() { if (collected) transform.localScale = Vector3.one * .5f; } public virtual 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); } } }