Added stations to loadout generator Overhauled Trade menu to sell station inventory contents Placing stations in ZoneGenerator Moved weapons to new item type: WeaponItemData Implemented icon sets for weapon functionality Renamed MegaCorporation to Faction Implemented quality-dependent item pricing Added unoccupied space helper function for entity Moved sector generation settings to settings file
839 lines
No EOL
32 KiB
C#
839 lines
No EOL
32 KiB
C#
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using Cinemachine;
|
|
using MessagePack;
|
|
using TMPro;
|
|
using UniRx;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
using UnityEngine.Rendering.PostProcessing;
|
|
using UnityEngine.Serialization;
|
|
using UnityEngine.UI;
|
|
using Unity.Mathematics;
|
|
using static Unity.Mathematics.math;
|
|
using float2 = Unity.Mathematics.float2;
|
|
using float3 = Unity.Mathematics.float3;
|
|
using quaternion = Unity.Mathematics.quaternion;
|
|
using Random = UnityEngine.Random;
|
|
|
|
public class ActionGameManager : MonoBehaviour
|
|
{
|
|
private static DirectoryInfo _gameDataDirectory;
|
|
public static DirectoryInfo GameDataDirectory
|
|
{
|
|
get => _gameDataDirectory ??= new DirectoryInfo(Application.dataPath).Parent.CreateSubdirectory("GameData");
|
|
}
|
|
|
|
private static DatabaseCache _database;
|
|
|
|
public static DatabaseCache Database
|
|
{
|
|
get
|
|
{
|
|
if (_database != null) return _database;
|
|
|
|
_database = new DatabaseCache(Path.Combine(GameDataDirectory.FullName, "AetherDB.msgpack"));
|
|
_database.Load();
|
|
|
|
return _database;
|
|
}
|
|
}
|
|
|
|
private static PlayerSettings _playerSettings;
|
|
public static PlayerSettings PlayerSettings
|
|
{
|
|
get => _playerSettings ??= File.Exists(_playerSettingsFilePath)
|
|
? MessagePackSerializer.Deserialize<PlayerSettings>(File.ReadAllBytes(_playerSettingsFilePath))
|
|
: new PlayerSettings {Name = Environment.UserName};
|
|
}
|
|
private static string _playerSettingsFilePath => Path.Combine(GameDataDirectory.FullName, "PlayerSettings.msgpack");
|
|
public static void SavePlayerSettings()
|
|
{
|
|
File.WriteAllBytes(_playerSettingsFilePath, MessagePackSerializer.Serialize(_playerSettings));
|
|
}
|
|
|
|
public static Sector CurrentSector;
|
|
|
|
public GameSettings Settings;
|
|
//public string StarterShipTemplate = "Longinus";
|
|
public float2 Sensitivity;
|
|
public int Credits = 15000000;
|
|
public float TargetSpottedBlinkFrequency = 20;
|
|
public float TargetSpottedBlinkOffset = -.25f;
|
|
|
|
[Header("Name Generation")]
|
|
public TextAsset NameFile;
|
|
public int NameGeneratorMinLength = 5;
|
|
public int NameGeneratorMaxLength = 10;
|
|
public int NameGeneratorOrder = 4;
|
|
|
|
[Header("Postprocessing")]
|
|
public float DeathPPTransitionTime;
|
|
public PostProcessVolume DeathPP;
|
|
public PostProcessVolume HeatstrokePP;
|
|
public PostProcessVolume SevereHeatstrokePP;
|
|
|
|
[Header("Scene Links")]
|
|
public TradeMenu TradeMenu;
|
|
public Prototype HostileTargetIndicator;
|
|
public PlaceUIElementWorldspace ViewDot;
|
|
public PlaceUIElementWorldspace TargetIndicator;
|
|
public Prototype LockIndicator;
|
|
public PlaceUIElementWorldspace[] Crosshairs;
|
|
public EventLog EventLog;
|
|
[FormerlySerializedAs("SectorRenderer")] public ZoneRenderer ZoneRenderer;
|
|
public CinemachineVirtualCamera DockCamera;
|
|
public CinemachineVirtualCamera FollowCamera;
|
|
public GameObject GameplayUI;
|
|
public MenuPanel Menu;
|
|
public MapRenderer MenuMap;
|
|
//public SectorRenderer SectorRenderer;
|
|
public SectorMap SectorMap;
|
|
public SchematicDisplay SchematicDisplay;
|
|
public SchematicDisplay TargetSchematicDisplay;
|
|
public InventoryMenu Inventory;
|
|
public InventoryPanel ShipPanel;
|
|
public InventoryPanel TargetShipPanel;
|
|
[FormerlySerializedAs("ConfirmationDialog")] public ConfirmationDialog Dialog;
|
|
|
|
//public PlayerInput Input;
|
|
|
|
// private CinemachineFramingTransposer _transposer;
|
|
// private CinemachineComposer _composer;
|
|
|
|
private DirectoryInfo _loadoutPath;
|
|
private bool _editMode;
|
|
private float _time;
|
|
private AetheriaInput _input;
|
|
private int _zoomLevelIndex;
|
|
private Entity _currentEntity;
|
|
|
|
// private ShipInput _shipInput;
|
|
private float2 _entityYawPitch;
|
|
private float3 _viewDirection;
|
|
private (HardpointData[] hardpoints, Transform[] barrels, PlaceUIElementWorldspace crosshair)[] _articulationGroups;
|
|
private (LockWeapon targetLock, PlaceUIElementWorldspace indicator, Rotate spin)[] _lockingIndicators;
|
|
private Dictionary<Entity, VisibleHostileIndicator> _visibleHostileIndicators = new Dictionary<Entity, VisibleHostileIndicator>();
|
|
private List<IDisposable> _shipSubscriptions = new List<IDisposable>();
|
|
private float _severeHeatstrokePhase;
|
|
|
|
public EquippedDockingBay DockingBay { get; private set; }
|
|
public Entity DockedEntity { get; private set; }
|
|
|
|
public Entity CurrentEntity
|
|
{
|
|
get => _currentEntity;
|
|
set => _currentEntity = value;
|
|
}
|
|
|
|
public ItemManager ItemManager { get; private set; }
|
|
public Zone Zone { get; private set; }
|
|
public List<EntityPack> Loadouts { get; } = new List<EntityPack>();
|
|
|
|
private readonly (float2 direction, string name)[] _directions = {
|
|
(float2(0, 1), "Front"),
|
|
(float2(1, 0), "Right"),
|
|
(float2(-1, 0), "Left"),
|
|
(float2(0, -1), "Rear")
|
|
};
|
|
|
|
public EntitySettings NewEntitySettings
|
|
{
|
|
get => MessagePackSerializer.Deserialize<EntitySettings>(MessagePackSerializer.Serialize(Settings.GameplaySettings.DefaultEntitySettings));
|
|
}
|
|
|
|
public void SaveLoadout(EntityPack pack)
|
|
{
|
|
File.WriteAllBytes(Path.Combine(_loadoutPath.FullName, $"{pack.Name}.loadout"), MessagePackSerializer.Serialize(pack));
|
|
}
|
|
|
|
private void OnApplicationQuit()
|
|
{
|
|
if(CurrentSector!=null)
|
|
{
|
|
SaveState();
|
|
}
|
|
}
|
|
|
|
public void SaveState()
|
|
{
|
|
PlayerSettings.CurrentRun = new SavedGame(CurrentSector, Zone, CurrentEntity);
|
|
SavePlayerSettings();
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
AkSoundEngine.RegisterGameObj(gameObject);
|
|
ConsoleController.MessageReceiver = this;
|
|
|
|
ItemManager = new ItemManager(Database, Settings.GameplaySettings, Debug.Log);
|
|
ZoneRenderer.ItemManager = ItemManager;
|
|
|
|
// _loadoutPath = GameDataDirectory.CreateSubdirectory("Loadouts");
|
|
// Loadouts.AddRange(_loadoutPath.EnumerateFiles("*.loadout")
|
|
// .Select(fi => MessagePackSerializer.Deserialize<EntityPack>(File.ReadAllBytes(fi.FullName))));
|
|
|
|
#region Input Handling
|
|
|
|
_input = new AetheriaInput();
|
|
_input.Global.Enable();
|
|
_input.UI.Enable();
|
|
|
|
_zoomLevelIndex = Settings.DefaultMinimapZoom;
|
|
_input.Player.MinimapZoom.performed += context =>
|
|
{
|
|
_zoomLevelIndex = (_zoomLevelIndex + 1) % Settings.MinimapZoomLevels.Length;
|
|
ZoneRenderer.MinimapDistance = Settings.MinimapZoomLevels[_zoomLevelIndex];
|
|
};
|
|
|
|
_input.Global.MapToggle.performed += context =>
|
|
{
|
|
if (Menu.gameObject.activeSelf && Menu.CurrentTab == MenuTab.Map)
|
|
{
|
|
Cursor.lockState = CursorLockMode.Locked;
|
|
Menu.gameObject.SetActive(false);
|
|
if (CurrentEntity != null && CurrentEntity.Parent == null)
|
|
{
|
|
_input.Player.Enable();
|
|
GameplayUI.SetActive(true);
|
|
|
|
SchematicDisplay.ShowShip(CurrentEntity);
|
|
ShipPanel.Display(CurrentEntity, true);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
Cursor.lockState = CursorLockMode.None;
|
|
_input.Player.Disable();
|
|
GameplayUI.SetActive(false);
|
|
Menu.ShowTab(MenuTab.Map);
|
|
MenuMap.Position = CurrentEntity.Position.xz;
|
|
};
|
|
|
|
_input.Global.Inventory.performed += context =>
|
|
{
|
|
if (Menu.gameObject.activeSelf && Menu.CurrentTab == MenuTab.Inventory)
|
|
{
|
|
Cursor.lockState = CursorLockMode.Locked;
|
|
Menu.gameObject.SetActive(false);
|
|
if (CurrentEntity != null && CurrentEntity.Parent == null)
|
|
{
|
|
_input.Player.Enable();
|
|
GameplayUI.SetActive(true);
|
|
|
|
SchematicDisplay.ShowShip(CurrentEntity);
|
|
ShipPanel.Display(CurrentEntity, true);
|
|
}
|
|
return;
|
|
}
|
|
|
|
Cursor.lockState = CursorLockMode.None;
|
|
_input.Player.Disable();
|
|
Menu.ShowTab(MenuTab.Inventory);
|
|
GameplayUI.SetActive(false);
|
|
};
|
|
|
|
_input.Global.Dock.performed += context =>
|
|
{
|
|
if (CurrentEntity == null)
|
|
{
|
|
AkSoundEngine.PostEvent("UI_Fail", gameObject);
|
|
Dialog.Clear();
|
|
Dialog.Title.text = "Can't undock. You dont have a ship!";
|
|
Dialog.Show();
|
|
Dialog.MoveToCursor();
|
|
}
|
|
else if (CurrentEntity.Parent == null) Dock();
|
|
else Undock();
|
|
};
|
|
|
|
_input.Player.EnterWormhole.performed += context =>
|
|
{
|
|
if(CurrentEntity is Ship ship)
|
|
{
|
|
foreach (var wormhole in ZoneRenderer.WormholeInstances.Keys)
|
|
{
|
|
if (length(wormhole.Position - CurrentEntity.Position.xz) < Settings.GameplaySettings.WormholeExitRadius)
|
|
{
|
|
var oldZone = Zone;
|
|
ship.EnterWormhole(wormhole.Position);
|
|
ship.OnEnteredWormhole += () =>
|
|
{
|
|
GenerateLevel(wormhole.Target);
|
|
ship.ExitWormhole(ZoneRenderer.WormholeInstances.Keys.First(w=>w.Target==oldZone.SectorZone).Position,
|
|
Settings.GameplaySettings.WormholeExitVelocity * ItemManager.Random.NextFloat2Direction());
|
|
CurrentEntity.Zone = Zone;
|
|
SaveState();
|
|
};
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
_input.Player.OverrideShutdown.performed += context =>
|
|
{
|
|
CurrentEntity.OverrideShutdown = !CurrentEntity.OverrideShutdown;
|
|
};
|
|
|
|
_input.Player.ToggleHeatsinks.performed += context =>
|
|
{
|
|
CurrentEntity.HeatsinksEnabled = !CurrentEntity.HeatsinksEnabled;
|
|
AkSoundEngine.PostEvent(CurrentEntity.HeatsinksEnabled ? "UI_Success" : "UI_Fail", gameObject);
|
|
};
|
|
|
|
_input.Player.ToggleShield.performed += context =>
|
|
{
|
|
if (CurrentEntity.Shield != null)
|
|
{
|
|
CurrentEntity.Shield.Item.Enabled.Value = !CurrentEntity.Shield.Item.Enabled.Value;
|
|
AkSoundEngine.PostEvent(CurrentEntity.Shield.Item.Enabled.Value ? "UI_Success" : "UI_Fail", gameObject);
|
|
}
|
|
};
|
|
|
|
#region Targeting
|
|
|
|
_input.Player.TargetReticle.performed += context =>
|
|
{
|
|
var underReticle = Zone.Entities.Where(x => x != CurrentEntity)
|
|
.MaxBy(x => dot(normalize(x.Position - CurrentEntity.Position), CurrentEntity.LookDirection));
|
|
CurrentEntity.Target.Value = CurrentEntity.Target.Value == underReticle ? null : underReticle;
|
|
};
|
|
|
|
_input.Player.TargetNearest.performed += context =>
|
|
{
|
|
CurrentEntity.Target.Value = Zone.Entities.Where(x=>x!=CurrentEntity)
|
|
.MaxBy(x => length(x.Position - CurrentEntity.Position));
|
|
};
|
|
|
|
_input.Player.TargetNext.performed += context =>
|
|
{
|
|
var targets = Zone.Entities.Where(x => x != CurrentEntity).OrderBy(x => length(x.Position - CurrentEntity.Position)).ToArray();
|
|
var currentTargetIndex = Array.IndexOf(targets, CurrentEntity.Target.Value);
|
|
CurrentEntity.Target.Value = targets[(currentTargetIndex + 1) % targets.Length];
|
|
};
|
|
|
|
_input.Player.TargetPrevious.performed += context =>
|
|
{
|
|
var targets = Zone.Entities.Where(x => x != CurrentEntity).OrderBy(x => length(x.Position - CurrentEntity.Position)).ToArray();
|
|
var currentTargetIndex = Array.IndexOf(targets, CurrentEntity.Target.Value);
|
|
CurrentEntity.Target.Value = targets[(currentTargetIndex + targets.Length - 1) % targets.Length];
|
|
};
|
|
|
|
#endregion
|
|
|
|
|
|
#region Trigger Groups
|
|
|
|
_input.Player.PreviousWeaponGroup.performed += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
SchematicDisplay.SelectedGroupIndex--;
|
|
};
|
|
|
|
_input.Player.NextWeaponGroup.performed += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
SchematicDisplay.SelectedGroupIndex++;
|
|
};
|
|
|
|
_input.Player.PreviousWeapon.performed += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
SchematicDisplay.SelectedItemIndex--;
|
|
};
|
|
|
|
_input.Player.NextWeapon.performed += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
SchematicDisplay.SelectedItemIndex++;
|
|
};
|
|
|
|
_input.Player.ToggleWeaponGroup.performed += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
var item = SchematicDisplay.SchematicItems[SchematicDisplay.SelectedItemIndex];
|
|
if (CurrentEntity.TriggerGroups[SchematicDisplay.SelectedGroupIndex].items.Contains(item.Item))
|
|
CurrentEntity.TriggerGroups[SchematicDisplay.SelectedGroupIndex].items.Remove(item.Item);
|
|
else CurrentEntity.TriggerGroups[SchematicDisplay.SelectedGroupIndex].items.Add(item.Item);
|
|
foreach (var group in item.Item.BehaviorGroups.Values)
|
|
{
|
|
var weapon = group.GetBehavior<Weapon>();
|
|
if(weapon != null)
|
|
{
|
|
if (CurrentEntity.TriggerGroups[SchematicDisplay.SelectedGroupIndex].weapons.Contains(weapon))
|
|
CurrentEntity.TriggerGroups[SchematicDisplay.SelectedGroupIndex].weapons.Remove(weapon);
|
|
else CurrentEntity.TriggerGroups[SchematicDisplay.SelectedGroupIndex].weapons.Add(weapon);
|
|
}
|
|
}
|
|
SchematicDisplay.UpdateTriggerGroups();
|
|
};
|
|
|
|
_input.Player.FireGroup1.started += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
foreach (var s in CurrentEntity.TriggerGroups[0].weapons) s.Activate();
|
|
};
|
|
|
|
_input.Player.FireGroup1.canceled += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
foreach (var s in CurrentEntity.TriggerGroups[0].weapons) s.Deactivate();
|
|
};
|
|
|
|
_input.Player.FireGroup2.started += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
foreach (var s in CurrentEntity.TriggerGroups[1].weapons) s.Activate();
|
|
};
|
|
|
|
_input.Player.FireGroup2.canceled += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
foreach (var s in CurrentEntity.TriggerGroups[1].weapons) s.Deactivate();
|
|
};
|
|
|
|
_input.Player.FireGroup3.started += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
foreach (var s in CurrentEntity.TriggerGroups[2].weapons) s.Activate();
|
|
};
|
|
|
|
_input.Player.FireGroup3.canceled += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
foreach (var s in CurrentEntity.TriggerGroups[2].weapons) s.Deactivate();
|
|
};
|
|
|
|
_input.Player.FireGroup4.started += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
foreach (var s in CurrentEntity.TriggerGroups[3].weapons) s.Activate();
|
|
};
|
|
|
|
_input.Player.FireGroup4.canceled += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
foreach (var s in CurrentEntity.TriggerGroups[3].weapons) s.Deactivate();
|
|
};
|
|
|
|
_input.Player.FireGroup5.started += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
foreach (var s in CurrentEntity.TriggerGroups[4].weapons) s.Activate();
|
|
};
|
|
|
|
_input.Player.FireGroup5.canceled += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
foreach (var s in CurrentEntity.TriggerGroups[4].weapons) s.Deactivate();
|
|
};
|
|
|
|
_input.Player.FireGroup6.started += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
foreach (var s in CurrentEntity.TriggerGroups[5].weapons) s.Activate();
|
|
};
|
|
|
|
_input.Player.FireGroup6.canceled += context =>
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
foreach (var s in CurrentEntity.TriggerGroups[5].weapons) s.Deactivate();
|
|
};
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
StartGame();
|
|
}
|
|
|
|
public void GenerateLevel(SectorZone sectorZone)
|
|
{
|
|
if (sectorZone == null) throw new ArgumentNullException(nameof(sectorZone));
|
|
|
|
if (sectorZone.Contents == null)
|
|
{
|
|
sectorZone.PackedContents ??= ZoneGenerator.GenerateZone(
|
|
ItemManager,
|
|
Settings.ZoneSettings,
|
|
CurrentSector,
|
|
sectorZone
|
|
);
|
|
sectorZone.Contents = new Zone(ItemManager, Settings.PlanetSettings, sectorZone.PackedContents, sectorZone);
|
|
}
|
|
Zone = sectorZone.Contents;
|
|
|
|
Zone.Log = s => Debug.Log($"Zone: {s}");
|
|
|
|
if (CurrentEntity != null)
|
|
{
|
|
CurrentEntity.Deactivate();
|
|
CurrentEntity.Zone.Entities.Remove(CurrentEntity);
|
|
CurrentEntity.Zone = Zone;
|
|
Zone.Entities.Add(CurrentEntity);
|
|
CurrentEntity.Activate();
|
|
}
|
|
|
|
ZoneRenderer.LoadZone(Zone);
|
|
|
|
if (CurrentEntity != null)
|
|
{
|
|
UnbindEntity();
|
|
BindToEntity(CurrentEntity);
|
|
}
|
|
}
|
|
|
|
private void StartGame()
|
|
{
|
|
if (CurrentSector != null)
|
|
{
|
|
if (PlayerSettings.CurrentRun == null)
|
|
{
|
|
GenerateLevel(CurrentSector.Entrance);
|
|
var loadoutGenerator = new LoadoutGenerator(ref ItemManager.Random, ItemManager, CurrentSector, Zone.SectorZone, null, 2);
|
|
var ship = EntitySerializer.Unpack(ItemManager, Zone, loadoutGenerator.GenerateShipLoadout(), true);
|
|
// EntitySerializer.Unpack(ItemManager, Zone, Loadouts.First(x => x.Name == StarterShipTemplate), true);
|
|
((Ship) ship).IsPlayerShip = true;
|
|
ship.Position = float3.zero;
|
|
ship.Zone = Zone;
|
|
Zone.Entities.Add(ship);
|
|
ship.Activate();
|
|
BindToEntity(ship);
|
|
}
|
|
else
|
|
{
|
|
GenerateLevel(CurrentSector.Zones[PlayerSettings.CurrentRun.CurrentZone]);
|
|
var targetEntity = Zone.Entities[PlayerSettings.CurrentRun.CurrentZoneEntity];
|
|
if (targetEntity is OrbitalEntity orbitalEntity)
|
|
DoDock(orbitalEntity, orbitalEntity.DockingBays.First());
|
|
else
|
|
BindToEntity(targetEntity);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Dock()
|
|
{
|
|
if (CurrentEntity.Parent != null) return;
|
|
if (CurrentEntity is Ship ship)
|
|
{
|
|
foreach (var entity in Zone.Entities.ToArray())
|
|
{
|
|
if (lengthsq(entity.Position.xz - CurrentEntity.Position.xz) <
|
|
Settings.GameplaySettings.DockingDistance * Settings.GameplaySettings.DockingDistance)
|
|
{
|
|
var bay = entity.TryDock(ship);
|
|
if (bay != null)
|
|
{
|
|
UnbindEntity();
|
|
DoDock(entity, bay);
|
|
TradeMenu.Inventory = entity.CargoBays.First();
|
|
AkSoundEngine.PostEvent("Dock", gameObject);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
AkSoundEngine.PostEvent("Dock_Fail", gameObject);
|
|
}
|
|
|
|
private void DoDock(Entity entity, EquippedDockingBay dockingBay)
|
|
{
|
|
DockedEntity = entity;
|
|
ZoneRenderer.PerspectiveEntity = DockedEntity;
|
|
DockingBay = dockingBay;
|
|
DockCamera.enabled = true;
|
|
FollowCamera.enabled = false;
|
|
var orbital = (OrbitalEntity) entity;
|
|
DockCamera.Follow = ZoneRenderer.EntityInstances[orbital].transform;
|
|
var parentOrbit = Zone.Orbits[orbital.OrbitData].Data.Parent;
|
|
var parentPlanet = ZoneRenderer.Planets[Zone.Planets.FirstOrDefault(p => p.Value.Orbit == parentOrbit).Key];
|
|
DockCamera.LookAt = parentPlanet.Body.transform;
|
|
Menu.ShowTab(MenuTab.Inventory);
|
|
}
|
|
|
|
public void Undock()
|
|
{
|
|
if (CurrentEntity.Parent == null) return;
|
|
if (CurrentEntity is Ship ship)
|
|
{
|
|
if (CurrentEntity.GetBehavior<Cockpit>() == null)
|
|
{
|
|
Dialog.Clear();
|
|
Dialog.Title.text = "Can't undock. Missing cockpit component!";
|
|
Dialog.Show();
|
|
Dialog.MoveToCursor();
|
|
AkSoundEngine.PostEvent("UI_Fail", gameObject);
|
|
}
|
|
else if (CurrentEntity.GetBehavior<Thruster>() == null)
|
|
{
|
|
Dialog.Clear();
|
|
Dialog.Title.text = "Can't undock. Missing thruster component!";
|
|
Dialog.Show();
|
|
Dialog.MoveToCursor();
|
|
AkSoundEngine.PostEvent("UI_Fail", gameObject);
|
|
}
|
|
else if (CurrentEntity.GetBehavior<Reactor>() == null)
|
|
{
|
|
Dialog.Clear();
|
|
Dialog.Title.text = "Can't undock. Missing reactor component!";
|
|
Dialog.Show();
|
|
Dialog.MoveToCursor();
|
|
AkSoundEngine.PostEvent("UI_Fail", gameObject);
|
|
}
|
|
else if (CurrentEntity.Parent.TryUndock(ship))
|
|
{
|
|
BindToEntity(ship);
|
|
AkSoundEngine.PostEvent("Undock", gameObject);
|
|
}
|
|
else
|
|
{
|
|
Dialog.Title.text = "Can't undock. Must empty docking bay!";
|
|
Dialog.Show();
|
|
Dialog.MoveToCursor();
|
|
AkSoundEngine.PostEvent("UI_Fail", gameObject);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UnbindEntity()
|
|
{
|
|
foreach (var indicator in _visibleHostileIndicators)
|
|
{
|
|
Destroy(indicator.Value.gameObject);
|
|
}
|
|
|
|
_visibleHostileIndicators.Clear();
|
|
if(_lockingIndicators!=null) foreach(var (_, indicator, _) in _lockingIndicators)
|
|
indicator.GetComponent<Prototype>().ReturnToPool();
|
|
_input.Player.Disable();
|
|
Cursor.lockState = CursorLockMode.None;
|
|
GameplayUI.SetActive(false);
|
|
|
|
foreach(var subscription in _shipSubscriptions) subscription.Dispose();
|
|
_shipSubscriptions.Clear();
|
|
}
|
|
|
|
private void BindToEntity(Entity entity)
|
|
{
|
|
if (!ZoneRenderer.EntityInstances.ContainsKey(entity))
|
|
{
|
|
Debug.LogError($"Attempted to bind to entity {entity.Name}, but SectorRenderer has no such instance!");
|
|
return;
|
|
}
|
|
|
|
CurrentEntity = entity;
|
|
DeathPP.weight = 0;
|
|
ZoneRenderer.PerspectiveEntity = CurrentEntity;
|
|
|
|
Menu.gameObject.SetActive(false);
|
|
DockedEntity = null;
|
|
DockingBay = null;
|
|
DockCamera.enabled = false;
|
|
FollowCamera.enabled = true;
|
|
|
|
Cursor.lockState = CursorLockMode.Locked;
|
|
GameplayUI.SetActive(true);
|
|
_input.Player.Enable();
|
|
ShipPanel.Display(CurrentEntity, true);
|
|
SchematicDisplay.ShowShip(CurrentEntity);
|
|
|
|
FollowCamera.LookAt = ZoneRenderer.EntityInstances[CurrentEntity].LookAtPoint;
|
|
FollowCamera.Follow = ZoneRenderer.EntityInstances[CurrentEntity].transform;
|
|
_articulationGroups = CurrentEntity.Equipment
|
|
.Where(item => item.Behaviors.Any(x => x.Data is WeaponData && !(x.Data is LauncherData)))
|
|
.GroupBy(item => ZoneRenderer.EntityInstances[CurrentEntity]
|
|
.GetBarrel(CurrentEntity.Hardpoints[item.Position.x, item.Position.y])
|
|
.GetComponentInParent<ArticulationPoint>()?.Group ?? -1)
|
|
.Select((group, index) => {
|
|
return (
|
|
group.Select(item => CurrentEntity.Hardpoints[item.Position.x, item.Position.y]).ToArray(),
|
|
group.Select(item => ZoneRenderer.EntityInstances[CurrentEntity].GetBarrel(CurrentEntity.Hardpoints[item.Position.x, item.Position.y])).ToArray(),
|
|
Crosshairs[index]
|
|
);
|
|
}).ToArray();
|
|
|
|
foreach (var crosshair in Crosshairs)
|
|
crosshair.gameObject.SetActive(false);
|
|
foreach (var group in _articulationGroups)
|
|
group.crosshair.gameObject.SetActive(true);
|
|
|
|
_shipSubscriptions.Add(CurrentEntity.Target.Subscribe(target =>
|
|
{
|
|
TargetIndicator.gameObject.SetActive(CurrentEntity.Target.Value != null);
|
|
TargetShipPanel.gameObject.SetActive(target != null);
|
|
if (target != null)
|
|
{
|
|
TargetShipPanel.Display(target, true);
|
|
TargetSchematicDisplay.ShowShip(target, CurrentEntity);
|
|
}
|
|
}));
|
|
|
|
foreach (var hostile in CurrentEntity.VisibleHostiles)
|
|
{
|
|
var indicator = HostileTargetIndicator.Instantiate<VisibleHostileIndicator>();
|
|
_visibleHostileIndicators.Add(hostile, indicator);
|
|
}
|
|
_shipSubscriptions.Add(CurrentEntity.VisibleHostiles.ObserveAdd().Subscribe(addEvent =>
|
|
{
|
|
var indicator = HostileTargetIndicator.Instantiate<VisibleHostileIndicator>();
|
|
_visibleHostileIndicators.Add(addEvent.Value, indicator);
|
|
}));
|
|
_shipSubscriptions.Add(CurrentEntity.VisibleHostiles.ObserveRemove().Subscribe(removeEvent =>
|
|
{
|
|
_visibleHostileIndicators[removeEvent.Value].GetComponent<Prototype>().ReturnToPool();
|
|
_visibleHostileIndicators.Remove(removeEvent.Value);
|
|
}));
|
|
|
|
_shipSubscriptions.Add(CurrentEntity.Death.Subscribe(_ =>
|
|
{
|
|
var deathTime = Time.time;
|
|
UnbindEntity();
|
|
CurrentEntity = null;
|
|
Dialog.Clear();
|
|
Dialog.Title.text = "You have died!";
|
|
Dialog.Show(() =>
|
|
{
|
|
PlayerSettings.CurrentRun = null;
|
|
StartGame();
|
|
}, null, "Try again!");
|
|
Dialog.transform.position = new Vector3(Screen.width / 2, Screen.height / 2);
|
|
//Dialog.MoveToCursor();
|
|
Observable.EveryUpdate()
|
|
.Select(_ => (Time.time - deathTime) / DeathPPTransitionTime)
|
|
.Where(t => t < 1)
|
|
.Subscribe(t =>
|
|
{
|
|
HeatstrokePP.weight = 1 - t;
|
|
SevereHeatstrokePP.weight = 1 - t;
|
|
DeathPP.weight = t;
|
|
}, () =>
|
|
{
|
|
HeatstrokePP.weight = 0;
|
|
SevereHeatstrokePP.weight = 0;
|
|
DeathPP.weight = 1;
|
|
});
|
|
}));
|
|
|
|
_lockingIndicators = CurrentEntity.GetBehaviors<LockWeapon>()
|
|
.Select(x =>
|
|
{
|
|
var i = LockIndicator.Instantiate<PlaceUIElementWorldspace>();
|
|
return (x, i, i.GetComponent<Rotate>());
|
|
}).ToArray();
|
|
}
|
|
|
|
public void SaveZone(string name) => File.WriteAllBytes(
|
|
Path.Combine(_gameDataDirectory.FullName, $"{name}.zone"), MessagePackSerializer.Serialize(Zone.PackZone()));
|
|
|
|
// public void ToggleEditMode()
|
|
// {
|
|
// _editMode = !_editMode;
|
|
// FollowCamera.gameObject.SetActive(!_editMode);
|
|
// TopDownCamera.gameObject.SetActive(_editMode);
|
|
// }
|
|
|
|
public IEnumerable<EquippedCargoBay> AvailableCargoBays()
|
|
{
|
|
if (CurrentEntity.Parent != null)
|
|
{
|
|
foreach (var bay in CurrentEntity.Parent.DockingBays)
|
|
{
|
|
if (bay.DockedShip.IsPlayerShip) yield return bay;
|
|
}
|
|
}
|
|
}
|
|
|
|
public IEnumerable<Entity> AvailableEntities()
|
|
{
|
|
if(DockedEntity != null)
|
|
foreach (var entity in DockedEntity.Children)
|
|
{
|
|
if (entity is Ship { IsPlayerShip: true }) yield return entity;
|
|
}
|
|
else if (CurrentEntity != null)
|
|
yield return CurrentEntity;
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if(!_editMode)
|
|
{
|
|
_time += Time.deltaTime;
|
|
ItemManager.Time = Time.time;
|
|
if(CurrentEntity !=null && CurrentEntity.Parent==null)
|
|
{
|
|
foreach (var indicator in _visibleHostileIndicators)
|
|
{
|
|
indicator.Value.gameObject.SetActive(indicator.Key!=CurrentEntity.Target.Value);
|
|
indicator.Value.Place.Target = indicator.Key.Position;
|
|
indicator.Value.Fill.fillAmount =
|
|
saturate(indicator.Key.EntityInfoGathered[CurrentEntity] / Settings.GameplaySettings.TargetDetectionInfoThreshold);
|
|
indicator.Value.Fill.enabled =
|
|
!(indicator.Key.EntityInfoGathered[CurrentEntity] > Settings.GameplaySettings.TargetDetectionInfoThreshold) ||
|
|
sin(TargetSpottedBlinkFrequency * Time.time) + TargetSpottedBlinkOffset > 0;
|
|
}
|
|
var look = _input.Player.Look.ReadValue<Vector2>();
|
|
_entityYawPitch = float2(_entityYawPitch.x + look.x * Sensitivity.x, clamp(_entityYawPitch.y + look.y * Sensitivity.y, -.45f * PI, .45f * PI));
|
|
_viewDirection = mul(float3(0, 0, 1), Unity.Mathematics.float3x3.Euler(float3(_entityYawPitch.yx, 0), RotationOrder.YXZ));
|
|
CurrentEntity.LookDirection = _viewDirection;
|
|
HeatstrokePP.weight = saturate(unlerp(0, Settings.GameplaySettings.SevereHeatstrokeRiskThreshold, CurrentEntity.Heatstroke));
|
|
var severeHeatstrokeLerp = saturate(unlerp(Settings.GameplaySettings.SevereHeatstrokeRiskThreshold, 1, CurrentEntity.Heatstroke));
|
|
SevereHeatstrokePP.weight =
|
|
severeHeatstrokeLerp + severeHeatstrokeLerp * (1 - severeHeatstrokeLerp) *
|
|
max(Settings.HeatstrokePhasingFloor, sin(Time.time * Settings.HeatstrokePhasingFrequency));
|
|
|
|
if(CurrentEntity is Ship ship)
|
|
{
|
|
ship.MovementDirection = _input.Player.Move.ReadValue<Vector2>();
|
|
}
|
|
}
|
|
}
|
|
Zone.Update(_time, Time.deltaTime);
|
|
ZoneRenderer.GameTime = _time;
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
UpdateTargetIndicators();
|
|
}
|
|
|
|
private void UpdateTargetIndicators()
|
|
{
|
|
if (CurrentEntity == null || CurrentEntity.Parent != null) return;
|
|
|
|
ViewDot.Target = ZoneRenderer.EntityInstances[CurrentEntity].LookAtPoint.position;
|
|
if (CurrentEntity.Target.Value != null)
|
|
TargetIndicator.Target = CurrentEntity.Target.Value.Position;
|
|
var distance = length((float3)ViewDot.Target - CurrentEntity.Position);
|
|
foreach (var (_, barrels, crosshair) in _articulationGroups)
|
|
{
|
|
var averagePosition = Vector3.zero;
|
|
foreach (var barrel in barrels)
|
|
averagePosition += barrel.position + barrel.forward * distance;
|
|
averagePosition /= barrels.Length;
|
|
crosshair.Target = averagePosition;
|
|
}
|
|
|
|
foreach (var (targetLock, indicator, spin) in _lockingIndicators)
|
|
{
|
|
var showLockingIndicator = targetLock.Lock > .01f && CurrentEntity.Target.Value != null && CurrentEntity.Target.Value.IsHostileTo(CurrentEntity);
|
|
indicator.gameObject.SetActive(showLockingIndicator);
|
|
if(showLockingIndicator)
|
|
{
|
|
indicator.Target = CurrentEntity.Target.Value.Position;
|
|
indicator.NoiseAmplitude = Settings.GameplaySettings.LockIndicatorNoiseAmplitude * (1 - targetLock.Lock);
|
|
indicator.NoiseFrequency = Settings.GameplaySettings.LockIndicatorFrequency.Evaluate(targetLock.Lock);
|
|
spin.Speed = Settings.GameplaySettings.LockSpinSpeed.Evaluate(targetLock.Lock);
|
|
}
|
|
}
|
|
}
|
|
} |