Files
unity/Assets/Game/Scripts/Runs/WarzoneDirector.cs

294 lines
14 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 relay, onwardGate, terminalTarget;
public Transform NavigationTarget => game.Run.routeCompleted ? null :
!game.Trial && game.Run.stage == 4 ? terminalTarget :
game.Run.objectiveDone ? onwardGate : relay;
public Vector3 ExtractionPosition => extractionPosition;
readonly System.Collections.Generic.List<Rect> cover = new System.Collections.Generic.List<Rect>();
public System.Collections.Generic.IReadOnlyList<Rect> Cover => cover;
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;
relay = onwardGate = terminalTarget = null;
cover.Clear();
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;
cover.Add(new Rect(x - 2.75f, z - 1.5f, 5.5f, 3));
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);
relay = objective.transform;
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);
onwardGate = onward.transform;
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);
terminalTarget = cart.transform;
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;
if (type == 3)
terminalTarget = obj.transform;
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", game.Settings.Bindings.Display("Interact"));
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;
string interact = g.Settings.Bindings.Display("Interact");
if (kind == 0)
return GameLocalization.Text("prompt.search", interact);
if (kind == 1)
return GameLocalization.Text(g.Run.objectiveDone ? "prompt.relayOnline" : "prompt.objective", interact);
if (kind == 2)
return GameLocalization.Text(g.Run.objectiveDone ? "prompt.route" : "prompt.routeLocked", interact);
return GameLocalization.Text(g.World.TransportReady ? "prompt.board" : g.World.ExtractionRemaining >= 0 ? "prompt.inbound" : "prompt.call", interact);
}
}
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);
}
}
}