Combat & Visibility & Collisions
Converted entity materials to new fade shader Implemented visibility system Refactored per-instance entity code to run inside monobehavior on entity instances Created state machine AI for enemy ships with basic patrol and combat routines Removed legacy AI code (controller item behaviors) Added automatic trigger group assignment for matched weapons Created ship collision system Created shield VFX and colliders
This commit is contained in:
parent
8d4bd04891
commit
b53e4aec8c
204 changed files with 8182 additions and 1919 deletions
|
|
@ -5,6 +5,9 @@ using static Unity.Mathematics.math;
|
|||
|
||||
public static class AetheriaMath
|
||||
{
|
||||
public const float Deg2Rad = 0.01745329f;
|
||||
public const float Rad2Deg = 57.29578f;
|
||||
|
||||
//first-order intercept using absolute target position
|
||||
public static float3 FirstOrderIntercept
|
||||
(
|
||||
|
|
|
|||
96
Assets/Scripts/ServerShared/Agents/Agent.cs
Normal file
96
Assets/Scripts/ServerShared/Agents/Agent.cs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/* 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.Linq;
|
||||
using RethinkDb.Driver.Ast;
|
||||
using UniRx;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
using float2 = Unity.Mathematics.float2;
|
||||
|
||||
public class Agent
|
||||
{
|
||||
private const float FORWARD_DELTA_THRESHOLD = 20;
|
||||
private const float THRUST_DELTA_THRESHOLD = 1;
|
||||
protected BaseState _rootState;
|
||||
private BaseState _currentState;
|
||||
private VelocityLimit _velocityLimit;
|
||||
|
||||
public AgentTask Task { get; set; }
|
||||
public Ship Ship { get; }
|
||||
public ItemManager ItemManager { get; }
|
||||
public GameplaySettings Settings { get; }
|
||||
public float TopSpeed => _velocityLimit?.Limit ?? 100;
|
||||
|
||||
public Agent(Ship ship)
|
||||
{
|
||||
Ship = ship;
|
||||
ItemManager = Ship.ItemManager;
|
||||
Settings = Ship.ItemManager.GameplaySettings;
|
||||
|
||||
_rootState = _currentState = new BaseState(this);
|
||||
_velocityLimit = Ship.GetBehavior<VelocityLimit>();
|
||||
}
|
||||
|
||||
public void Transition(BaseState targetState, Action onTransition = null)
|
||||
{
|
||||
ItemManager.Log($"{Ship.Name} changing state from {_currentState.GetType().Name} to {targetState.GetType().Name}");
|
||||
_currentState.OnExitState();
|
||||
_currentState = targetState;
|
||||
onTransition?.Invoke();
|
||||
_currentState.OnEnterState();
|
||||
}
|
||||
|
||||
public void Update(float delta)
|
||||
{
|
||||
_currentState.Update(delta);
|
||||
foreach (var transition in _currentState.Transitions)
|
||||
if (transition.Condition())
|
||||
{
|
||||
Transition(transition.TargetState, transition.OnTransition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Accelerate(float2 targetVelocity, bool noTurn = false)
|
||||
{
|
||||
var deltaV = targetVelocity - Ship.Velocity;
|
||||
var deltaVMag = length(deltaV);
|
||||
var deltaVDirection = normalize(deltaV);
|
||||
// If Delta V is above the threshold, direct the ship towards the delta and use only main thrusters
|
||||
if (!noTurn && deltaVMag > FORWARD_DELTA_THRESHOLD)
|
||||
{
|
||||
Ship.LookDirection = float3(deltaVDirection.x, 0, deltaVDirection.y);
|
||||
Ship.MovementDirection = float2(0, pow(dot(Ship.Direction, deltaVDirection), 2));
|
||||
}
|
||||
// If Delta V is low, direct the ship towards the target and use all thrusters
|
||||
else if(deltaVMag > THRUST_DELTA_THRESHOLD)
|
||||
{
|
||||
var right = Ship.Direction.Rotate(ItemRotation.Clockwise);
|
||||
Ship.MovementDirection = float2(dot(right, deltaVDirection), dot(Ship.Direction, deltaVDirection));
|
||||
}
|
||||
else
|
||||
{
|
||||
Ship.MovementDirection = float2.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class StateTransition
|
||||
{
|
||||
public StateTransition(BaseState targetState, Func<bool> condition, Action onTransition)
|
||||
{
|
||||
TargetState = targetState;
|
||||
Condition = condition;
|
||||
OnTransition = onTransition;
|
||||
}
|
||||
|
||||
public BaseState TargetState { get; }
|
||||
public Func<bool> Condition { get; }
|
||||
public Action OnTransition { get; }
|
||||
}
|
||||
|
||||
|
|
@ -1,203 +0,0 @@
|
|||
/* 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.Linq;
|
||||
using RethinkDb.Driver.Ast;
|
||||
using UniRx;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
using float2 = Unity.Mathematics.float2;
|
||||
|
||||
public abstract class AgentBehavior
|
||||
{
|
||||
public abstract void Update(float delta);
|
||||
|
||||
protected float ThrustInput(float2 deltaV) =>
|
||||
saturate( // Input must be normalized
|
||||
pow( // Apply specificity as exponent to dot product to control how specific the direction needs to be
|
||||
saturate( // Discard negative dot product (we're facing away from desired direction)
|
||||
dot(normalize(Entity.Direction), normalize(deltaV))), // Cosine of angle between direction and deltaV
|
||||
ControllerData.ThrustSpecificity)
|
||||
* length(deltaV) * ControllerData.ThrustSensitivity);
|
||||
|
||||
protected float TurningInput(float2 deltaV) => clamp(-Entity.Direction.AngleDiff(deltaV) * ControllerData.TurningSensitivity, -1, 1);
|
||||
|
||||
protected ControllerData ControllerData;
|
||||
protected ItemManager Context;
|
||||
protected Entity Entity;
|
||||
|
||||
public AgentBehavior(ItemManager context, Entity entity, ControllerData controllerData)
|
||||
{
|
||||
Context = context;
|
||||
Entity = entity;
|
||||
ControllerData = controllerData;
|
||||
}
|
||||
}
|
||||
|
||||
public class Agent
|
||||
{
|
||||
private BaseState _rootState;
|
||||
private BaseState _currentState;
|
||||
private Dictionary<BaseState, List<StateTransition>> _stateTransitions = new Dictionary<BaseState, List<StateTransition>>();
|
||||
|
||||
public AgentTask Task { get; set; }
|
||||
public Ship Ship { get; }
|
||||
public ItemManager ItemManager { get; }
|
||||
public GameplaySettings Settings { get; }
|
||||
|
||||
public Agent(Ship ship)
|
||||
{
|
||||
Ship = ship;
|
||||
ItemManager = Ship.ItemManager;
|
||||
Settings = Ship.ItemManager.GameplaySettings;
|
||||
|
||||
_rootState = _currentState = new BaseState(this);
|
||||
|
||||
var patrolState = new PatrolOrbitsState(this);
|
||||
AddTransition(_rootState, patrolState,
|
||||
() => Task is PatrolOrbitsTask,
|
||||
() => patrolState.Task = Task as PatrolOrbitsTask);
|
||||
var patrolMoveState = new MoveToOrbitState(this);
|
||||
AddTransition(patrolState, patrolMoveState,
|
||||
() => true,
|
||||
() => patrolMoveState.Orbit = patrolState.CurrentTarget);
|
||||
AddTransition(patrolMoveState, patrolState,
|
||||
() => patrolMoveState.Distance < 10,
|
||||
() => patrolState.NextTarget());
|
||||
}
|
||||
|
||||
public void AddTransition(BaseState source, BaseState targetState, Func<bool> condition, Action onTransition = null)
|
||||
{
|
||||
if(!_stateTransitions.ContainsKey(source))
|
||||
_stateTransitions[source] = new List<StateTransition>();
|
||||
_stateTransitions[source].Add(new StateTransition(targetState, condition, onTransition));
|
||||
}
|
||||
|
||||
public void Transition(BaseState targetState, Action onTransition = null)
|
||||
{
|
||||
_currentState.OnExitState();
|
||||
_currentState = targetState;
|
||||
onTransition?.Invoke();
|
||||
_currentState.OnEnterState();
|
||||
}
|
||||
|
||||
public void Update(float delta)
|
||||
{
|
||||
_currentState.Update(delta);
|
||||
foreach (var transition in _stateTransitions[_currentState])
|
||||
if (transition.Condition())
|
||||
{
|
||||
Transition(transition.TargetState, transition.OnTransition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public class StateTransition
|
||||
{
|
||||
public StateTransition(BaseState targetState, Func<bool> condition, Action onTransition)
|
||||
{
|
||||
TargetState = targetState;
|
||||
Condition = condition;
|
||||
OnTransition = onTransition;
|
||||
}
|
||||
|
||||
public BaseState TargetState { get; }
|
||||
public Func<bool> Condition { get; }
|
||||
public Action OnTransition { get; }
|
||||
}
|
||||
}
|
||||
|
||||
public class BaseState
|
||||
{
|
||||
protected Agent _agent;
|
||||
|
||||
public BaseState(Agent agent)
|
||||
{
|
||||
_agent = agent;
|
||||
}
|
||||
public virtual void Update(float delta){}
|
||||
public virtual void OnEnterState(){}
|
||||
public virtual void OnExitState(){}
|
||||
}
|
||||
|
||||
public abstract class MoveToState : BaseState
|
||||
{
|
||||
private const float FORWARD_DELTA_THRESHOLD = 20;
|
||||
private const float THRUST_DELTA_THRESHOLD = 1;
|
||||
private VelocityLimit _velocityLimit;
|
||||
protected abstract float2 TargetPosition { get; }
|
||||
public float Distance { get; private set; }
|
||||
|
||||
protected MoveToState(Agent agent) : base(agent)
|
||||
{
|
||||
_velocityLimit = agent.Ship.GetBehavior<VelocityLimit>();
|
||||
}
|
||||
|
||||
public override void Update(float delta)
|
||||
{
|
||||
var diff = TargetPosition - _agent.Ship.Position.xz;
|
||||
var dir = normalize(diff);
|
||||
Distance = length(diff);
|
||||
|
||||
// We want to go top speed in the direction of our target
|
||||
var topSpeed = _velocityLimit?.Limit ?? 100;
|
||||
var desiredVelocity = dir * topSpeed;
|
||||
var deltaV = desiredVelocity - _agent.Ship.Velocity;
|
||||
var deltaVMag = length(deltaV);
|
||||
var deltaVDirection = normalize(deltaV);
|
||||
// If Delta V is above the threshold, direct the ship towards the delta and use only main thrusters
|
||||
if (deltaVMag > FORWARD_DELTA_THRESHOLD)
|
||||
{
|
||||
_agent.Ship.LookDirection = float3(deltaVDirection.x, 0, deltaVDirection.y);
|
||||
_agent.Ship.MovementDirection = float2(0, pow(dot(_agent.Ship.Direction, deltaVDirection), 2));
|
||||
}
|
||||
// If Delta V is low, direct the ship towards the target and use all thrusters
|
||||
else if(deltaVMag > THRUST_DELTA_THRESHOLD)
|
||||
{
|
||||
var right = _agent.Ship.Direction.Rotate(ItemRotation.Clockwise);
|
||||
_agent.Ship.LookDirection = float3(dir.x, 0, dir.y);
|
||||
_agent.Ship.MovementDirection = float2(dot(right, deltaVDirection), dot(_agent.Ship.Direction, deltaVDirection));
|
||||
}
|
||||
else
|
||||
{
|
||||
_agent.Ship.LookDirection = float3(dir.x, 0, dir.y);
|
||||
_agent.Ship.MovementDirection = float2.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MoveToEntityState : MoveToState
|
||||
{
|
||||
public Entity TargetEntity { get; set; }
|
||||
protected override float2 TargetPosition => TargetEntity?.Position.xz ?? float2.zero;
|
||||
|
||||
public MoveToEntityState(Agent agent) : base(agent) { }
|
||||
}
|
||||
|
||||
public class MoveToOrbitState : MoveToState
|
||||
{
|
||||
public Guid Orbit { get; set; }
|
||||
public MoveToOrbitState(Agent agent) : base(agent) { }
|
||||
|
||||
protected override float2 TargetPosition => _agent.Ship.Zone.GetOrbitPosition(Orbit);
|
||||
}
|
||||
|
||||
public class PatrolOrbitsState : BaseState
|
||||
{
|
||||
public PatrolOrbitsTask Task;
|
||||
public Guid CurrentTarget
|
||||
{
|
||||
get => Task.Circuit[_currentTargetIndex];
|
||||
}
|
||||
private int _currentTargetIndex;
|
||||
public void NextTarget()
|
||||
{
|
||||
_currentTargetIndex++;
|
||||
_currentTargetIndex %= Task.Circuit.Length;
|
||||
}
|
||||
public PatrolOrbitsState(Agent agent) : base(agent) { }
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/* 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.Linq;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
public class Locomotion : AgentBehavior
|
||||
{
|
||||
public float2 Objective;
|
||||
private const float TangentSensitivity = 2;
|
||||
|
||||
private VelocityLimit _velocityLimit;
|
||||
private Thruster[] _thrusters;
|
||||
private float _thrust;
|
||||
|
||||
public Locomotion(ItemManager context, Entity entity, ControllerData controllerData) : base(context, entity, controllerData)
|
||||
{
|
||||
_velocityLimit = Entity.GetBehavior<VelocityLimit>();
|
||||
_thrusters = entity.GetBehaviors<Thruster>()
|
||||
.Where(t => t.Item.EquippableItem.Rotation == ItemRotation.Reversed)
|
||||
.ToArray();
|
||||
_thrust = _thrusters.Sum(t => t.Thrust);
|
||||
}
|
||||
|
||||
public override void Update(float delta)
|
||||
{
|
||||
var diff = Objective - Entity.Position.xz;
|
||||
|
||||
// We want to go top speed in the direction of our target
|
||||
var topSpeed = _velocityLimit?.Limit ?? 100;
|
||||
float2 desiredVelocity = normalize(diff) * topSpeed;
|
||||
|
||||
var accelerationTime = length(desiredVelocity - Entity.Velocity) / (_thrust / Entity.Mass);
|
||||
var accelerationDistance = accelerationTime * length((desiredVelocity + Entity.Velocity) / 2);
|
||||
|
||||
// We do not have enough space to get to full speed, use approximate maneuvering
|
||||
// if (accelerationDistance > length(diff))
|
||||
// {
|
||||
// float2 tangential = Entity.Velocity - dot(normalize(diff), normalize(Entity.Velocity)) * Entity.Velocity;
|
||||
// float2 adjustedDirection = normalize(diff) - tangential * TangentSensitivity;
|
||||
//
|
||||
// _turning.Axis = TurningInput(adjustedDirection);
|
||||
// _thrust.Axis = 1;
|
||||
// }
|
||||
// // We have plenty of space, use exact maneuvering
|
||||
// else
|
||||
// {
|
||||
// var deltaV = desiredVelocity - Entity.Velocity;
|
||||
// _turning.Axis = TurningInput(deltaV);
|
||||
// _thrust.Axis = ThrustInput(deltaV);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c3af5050375d08242a52bdf7f7de558e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
23
Assets/Scripts/ServerShared/Agents/Minion.cs
Normal file
23
Assets/Scripts/ServerShared/Agents/Minion.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
using System.Linq;
|
||||
using UniRx;
|
||||
|
||||
public class Minion : Agent
|
||||
{
|
||||
public Minion(Ship ship) : base(ship)
|
||||
{
|
||||
var patrolState = new PatrolOrbitsState(this);
|
||||
_rootState.AddTransition(patrolState,
|
||||
() => Task is PatrolOrbitsTask,
|
||||
() => patrolState.Task = Task as PatrolOrbitsTask);
|
||||
|
||||
Ship.VisibleHostiles.ObserveAdd().Where(_ => Ship.Target.Value == null).Subscribe(add => Ship.Target.Value = add.Value);
|
||||
|
||||
var combatState = new CombatState(this);
|
||||
_rootState.AddTransition(combatState,
|
||||
() => Ship.Target.Value != null, null, true, _rootState);
|
||||
|
||||
combatState.AddTransition(_rootState,
|
||||
() => Ship.Target.Value == null, null, true, _rootState);
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/ServerShared/Agents/Minion.cs.meta
Normal file
3
Assets/Scripts/ServerShared/Agents/Minion.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b764e85a1fbe4d68abcc77480d6523e3
|
||||
timeCreated: 1613182738
|
||||
3
Assets/Scripts/ServerShared/Agents/States.meta
Normal file
3
Assets/Scripts/ServerShared/Agents/States.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 823a891ccfdd4b13be60053a85bfc073
|
||||
timeCreated: 1613182847
|
||||
63
Assets/Scripts/ServerShared/Agents/States/BaseState.cs
Normal file
63
Assets/Scripts/ServerShared/Agents/States/BaseState.cs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class BaseState
|
||||
{
|
||||
public List<StateTransition> Transitions { get; } = new List<StateTransition>();
|
||||
protected Agent _agent;
|
||||
|
||||
|
||||
public BaseState(Agent agent)
|
||||
{
|
||||
_agent = agent;
|
||||
}
|
||||
|
||||
private static List<BaseState> _lastVisitedStates = new List<BaseState>();
|
||||
private static List<BaseState> _leafStates = new List<BaseState>();
|
||||
private static List<BaseState> _visitedStates = new List<BaseState>();
|
||||
private static HashSet<BaseState> _ignoreStates = new HashSet<BaseState>();
|
||||
public void AddTransition(BaseState targetState, Func<bool> condition, Action onTransition = null, bool includeChildren = false, params BaseState[] ignoreStates)
|
||||
{
|
||||
Transitions.Add(new StateTransition(targetState, condition, onTransition));
|
||||
|
||||
// Traverse the state graph, adding every state that is reachable from this state without traversing over ignored nodes
|
||||
if (includeChildren)
|
||||
{
|
||||
_visitedStates.Clear();
|
||||
_ignoreStates.Clear();
|
||||
if(ignoreStates!=null)
|
||||
foreach (var ignoreState in ignoreStates)
|
||||
_ignoreStates.Add(ignoreState);
|
||||
_leafStates.Clear();
|
||||
_leafStates.Add(this);
|
||||
_ignoreStates.Add(this);
|
||||
_ignoreStates.Add(targetState);
|
||||
while (_leafStates.Count > 0)
|
||||
{
|
||||
_lastVisitedStates.Clear();
|
||||
_lastVisitedStates.AddRange(_leafStates);
|
||||
_leafStates.Clear();
|
||||
foreach (var state in _lastVisitedStates)
|
||||
{
|
||||
foreach (var transition in state.Transitions)
|
||||
{
|
||||
if(!_ignoreStates.Contains(transition.TargetState))
|
||||
{
|
||||
_visitedStates.Add(transition.TargetState);
|
||||
_ignoreStates.Add(transition.TargetState);
|
||||
_leafStates.Add(transition.TargetState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var state in _visitedStates)
|
||||
{
|
||||
state.AddTransition(targetState, condition, onTransition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Update(float delta){}
|
||||
public virtual void OnEnterState(){}
|
||||
public virtual void OnExitState(){}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a3f09ceb47034c18b938cb8732df690b
|
||||
timeCreated: 1613182963
|
||||
150
Assets/Scripts/ServerShared/Agents/States/Combat.cs
Normal file
150
Assets/Scripts/ServerShared/Agents/States/Combat.cs
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static Unity.Mathematics.math;
|
||||
using float2 = Unity.Mathematics.float2;
|
||||
using float3 = Unity.Mathematics.float3;
|
||||
using float2x2 = Unity.Mathematics.float2x2;
|
||||
|
||||
public class CombatState : BaseState
|
||||
{
|
||||
private const int DPS_SAMPLE_COUNT = 32;
|
||||
private float _optimumRange;
|
||||
private readonly List<(int index, float dps)> _availableGroups = new List<(int index, float dps)>();
|
||||
private readonly List<LockWeapon> _availableLockingWeapons = new List<LockWeapon>();
|
||||
|
||||
public CombatState(Agent agent) : base(agent)
|
||||
{
|
||||
SampleDps();
|
||||
foreach (var weapon in _agent.Ship.Weapons)
|
||||
{
|
||||
weapon.Item.OnDisable += SampleDps;
|
||||
weapon.Item.OnEnable += SampleDps;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float delta)
|
||||
{
|
||||
var target = _agent.Ship.Target.Value;
|
||||
if (target == null) return;
|
||||
|
||||
_availableGroups.Clear();
|
||||
_availableLockingWeapons.Clear();
|
||||
|
||||
var toTarget = target.Position - _agent.Ship.Position;
|
||||
var targetDistance = length(toTarget);
|
||||
for (var i = 0; i < _agent.Ship.TriggerGroups.Length; i++)
|
||||
{
|
||||
var group = _agent.Ship.TriggerGroups[i];
|
||||
var dps = 0f;
|
||||
foreach (var weapon in group.weapons)
|
||||
if (weapon.Item.Online &&
|
||||
weapon.MinRange < targetDistance &&
|
||||
targetDistance < weapon.Range &&
|
||||
(weapon is ConstantWeapon ||
|
||||
weapon is InstantWeapon instantWeapon && instantWeapon.CanFire))
|
||||
{
|
||||
if(weapon is LockWeapon lockWeapon)
|
||||
_availableLockingWeapons.Add(lockWeapon);
|
||||
else
|
||||
dps += weapon.RangeDamagePerSecond(targetDistance);
|
||||
}
|
||||
|
||||
if (dps > .1) _availableGroups.Add((i, dps));
|
||||
}
|
||||
|
||||
foreach(var w in _availableLockingWeapons) w.Activate();
|
||||
|
||||
var selectedGroup = -1;
|
||||
var maxDps = Single.MinValue;
|
||||
foreach (var group in _availableGroups)
|
||||
{
|
||||
if (group.dps > maxDps)
|
||||
{
|
||||
maxDps = group.dps;
|
||||
selectedGroup = group.index;
|
||||
}
|
||||
}
|
||||
|
||||
var targetRight = target.Direction.Rotate(ItemRotation.Clockwise);
|
||||
var optimumRangeDelta = abs(_optimumRange - targetDistance);
|
||||
var directionToTarget = normalize(toTarget.xz);
|
||||
var targetPortAlignment = dot(targetRight, directionToTarget);
|
||||
var targetForeAlignment = dot(-target.Direction, directionToTarget);
|
||||
var forwardness = saturate(optimumRangeDelta / _agent.Settings.AgentMaxForwardDistance) * _agent.Settings.AgentForwardLerp;
|
||||
if (targetForeAlignment > 0) forwardness = lerp(forwardness, 1, pow(targetPortAlignment, 2));
|
||||
|
||||
var movementDirection = normalize(lerp(
|
||||
directionToTarget.Rotate(targetPortAlignment > 0 ? ItemRotation.Clockwise : ItemRotation.CounterClockwise),
|
||||
targetDistance > _optimumRange ? directionToTarget : -directionToTarget, forwardness));
|
||||
|
||||
if (selectedGroup >= 0)
|
||||
{
|
||||
var testWeapon = _agent.Ship.TriggerGroups[selectedGroup].weapons.First();
|
||||
if(testWeapon.Velocity > 1)
|
||||
{
|
||||
var targetHullData = _agent.ItemManager.GetData(target.Hull) as HullData;
|
||||
var targetVelocity = float3(target.Velocity.x, 0, target.Velocity.y);
|
||||
var predictedPosition = AetheriaMath.FirstOrderIntercept(
|
||||
_agent.Ship.Position,
|
||||
float3.zero,
|
||||
testWeapon.Velocity,
|
||||
target.Position,
|
||||
targetVelocity
|
||||
);
|
||||
predictedPosition.y = _agent.Ship.Zone.GetHeight(predictedPosition.xz) + targetHullData.GridOffset;
|
||||
toTarget = normalize(predictedPosition - _agent.Ship.Position);
|
||||
}
|
||||
|
||||
var shouldFire = dot(
|
||||
_agent.Ship.HardpointTransforms[_agent.Ship.Hardpoints[testWeapon.Item.Position.x, testWeapon.Item.Position.y]].direction,
|
||||
toTarget) > .99f;
|
||||
foreach (var weapon in _agent.Ship.TriggerGroups[selectedGroup].weapons)
|
||||
{
|
||||
if (shouldFire)
|
||||
weapon.Activate();
|
||||
else if (weapon.Firing)
|
||||
weapon.Deactivate();
|
||||
}
|
||||
}
|
||||
_agent.Ship.LookDirection = toTarget;
|
||||
_agent.Accelerate(movementDirection * _agent.TopSpeed, true);//selectedGroup >= 0);
|
||||
|
||||
// Fire charged guns!
|
||||
}
|
||||
|
||||
private void SampleDps()
|
||||
{
|
||||
var minRange = Single.MaxValue;
|
||||
var maxRange = Single.MinValue;
|
||||
foreach (var weapon in _agent.Ship.Weapons)
|
||||
{
|
||||
if (weapon.Range < minRange)
|
||||
minRange = weapon.Range;
|
||||
if (weapon.Range > maxRange)
|
||||
maxRange = weapon.Range;
|
||||
}
|
||||
|
||||
var offset = _agent.ItemManager.Random.NextFloat((maxRange - minRange) / DPS_SAMPLE_COUNT);
|
||||
var optimumDPS = 0f;
|
||||
for (int i = 0; i < DPS_SAMPLE_COUNT; i++)
|
||||
{
|
||||
var range = offset + minRange + (maxRange - minRange) * ((float) i / DPS_SAMPLE_COUNT);
|
||||
float dps = 0;
|
||||
foreach (var weapon in _agent.Ship.Weapons)
|
||||
{
|
||||
if (weapon.Item.Online && weapon.MinRange < range && range < weapon.Range)
|
||||
dps += weapon.RangeDamagePerSecond(range);
|
||||
}
|
||||
|
||||
// Multiply by range raised to a (sublinear) exponent to bias DPS preference towards longer ranges
|
||||
dps *= pow(range, _agent.Settings.AgentRangeExponent);
|
||||
|
||||
if (dps > optimumDPS)
|
||||
{
|
||||
optimumDPS = dps;
|
||||
_optimumRange = range;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/ServerShared/Agents/States/Combat.cs.meta
Normal file
3
Assets/Scripts/ServerShared/Agents/States/Combat.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 059405941f2c482c8476a4b28196568e
|
||||
timeCreated: 1613189894
|
||||
32
Assets/Scripts/ServerShared/Agents/States/MatchVelocity.cs
Normal file
32
Assets/Scripts/ServerShared/Agents/States/MatchVelocity.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
using float2 = Unity.Mathematics.float2;
|
||||
|
||||
public abstract class MatchVelocityState : BaseState
|
||||
{
|
||||
protected abstract float2 TargetVelocity { get; }
|
||||
|
||||
protected MatchVelocityState(Agent agent) : base(agent) { }
|
||||
|
||||
public override void Update(float delta)
|
||||
{
|
||||
_agent.Accelerate(TargetVelocity);
|
||||
}
|
||||
|
||||
public float2 MatchDistanceTime
|
||||
{
|
||||
get
|
||||
{
|
||||
var velocity = length(_agent.Ship.Velocity);
|
||||
var deltaV = TargetVelocity - _agent.Ship.Velocity;
|
||||
|
||||
var stoppingTime = length(deltaV) / (_agent.Ship.ForwardThrust / _agent.Ship.Mass);
|
||||
var stoppingDistance = stoppingTime * (velocity / 2);
|
||||
|
||||
var turnaroundTime = _agent.Ship.TurnTime(deltaV);
|
||||
var turnaroundDistance = turnaroundTime * velocity;
|
||||
|
||||
return float2(stoppingDistance + turnaroundDistance, stoppingTime + turnaroundTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b584acceb113424a8fb7d1982e27b2db
|
||||
timeCreated: 1613185253
|
||||
44
Assets/Scripts/ServerShared/Agents/States/MoveTo.cs
Normal file
44
Assets/Scripts/ServerShared/Agents/States/MoveTo.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
using System;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
using float2 = Unity.Mathematics.float2;
|
||||
|
||||
public abstract class MoveToState : BaseState
|
||||
{
|
||||
private VelocityLimit _velocityLimit;
|
||||
protected abstract float2 TargetPosition { get; }
|
||||
public float Distance { get; private set; }
|
||||
|
||||
protected MoveToState(Agent agent) : base(agent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Update(float delta)
|
||||
{
|
||||
var diff = TargetPosition - _agent.Ship.Position.xz;
|
||||
var dir = normalize(diff);
|
||||
Distance = length(diff);
|
||||
|
||||
// We want to go top speed in the direction of our target
|
||||
var desiredVelocity = dir * _agent.TopSpeed;
|
||||
_agent.Ship.LookDirection = float3(dir.x, 0, dir.y);
|
||||
_agent.Accelerate(desiredVelocity);
|
||||
}
|
||||
}
|
||||
|
||||
public class MoveToEntityState : MoveToState
|
||||
{
|
||||
public Entity TargetEntity { get; set; }
|
||||
protected override float2 TargetPosition => TargetEntity?.Position.xz ?? float2.zero;
|
||||
|
||||
public MoveToEntityState(Agent agent) : base(agent) { }
|
||||
}
|
||||
|
||||
public class MoveToOrbitState : MoveToState
|
||||
{
|
||||
public Guid Orbit { get; set; }
|
||||
public MoveToOrbitState(Agent agent) : base(agent) { }
|
||||
|
||||
protected override float2 TargetPosition => _agent.Ship.Zone.GetOrbitPosition(Orbit);
|
||||
}
|
||||
3
Assets/Scripts/ServerShared/Agents/States/MoveTo.cs.meta
Normal file
3
Assets/Scripts/ServerShared/Agents/States/MoveTo.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ddb2b91d6c3340ccadfc7c20020846e8
|
||||
timeCreated: 1613182864
|
||||
3
Assets/Scripts/ServerShared/Agents/Tasks.meta
Normal file
3
Assets/Scripts/ServerShared/Agents/Tasks.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b9d106c37ec34e29aab0c8ee52a7ed5d
|
||||
timeCreated: 1613182162
|
||||
|
|
@ -40,8 +40,3 @@ public enum TaskType
|
|||
Explore
|
||||
}
|
||||
|
||||
public class PatrolOrbitsTask : AgentTask
|
||||
{
|
||||
public override TaskType Type => TaskType.Defend;
|
||||
public Guid[] Circuit;
|
||||
}
|
||||
31
Assets/Scripts/ServerShared/Agents/Tasks/PatrolOrbits.cs
Normal file
31
Assets/Scripts/ServerShared/Agents/Tasks/PatrolOrbits.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
|
||||
public class PatrolOrbitsTask : AgentTask
|
||||
{
|
||||
public override TaskType Type => TaskType.Defend;
|
||||
public Guid[] Circuit;
|
||||
}
|
||||
|
||||
public class PatrolOrbitsState : BaseState
|
||||
{
|
||||
public PatrolOrbitsTask Task;
|
||||
public Guid CurrentTarget
|
||||
{
|
||||
get => Task.Circuit[_currentTargetIndex];
|
||||
}
|
||||
private int _currentTargetIndex;
|
||||
public void NextTarget()
|
||||
{
|
||||
_currentTargetIndex++;
|
||||
_currentTargetIndex %= Task.Circuit.Length;
|
||||
}
|
||||
|
||||
public PatrolOrbitsState(Agent agent) : base(agent)
|
||||
{
|
||||
var patrolMoveState = new MoveToOrbitState(agent);
|
||||
Transitions.Add(new StateTransition(patrolMoveState,
|
||||
() => true,
|
||||
() => patrolMoveState.Orbit = CurrentTarget));
|
||||
patrolMoveState.Transitions.Add(new StateTransition(this, () => patrolMoveState.Distance < 10, NextTarget));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dcfc94fde9bb4aa2ac3c7d88180689cb
|
||||
timeCreated: 1613182188
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/* 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.Linq;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
using float2 = Unity.Mathematics.float2;
|
||||
|
||||
public class VelocityMatch : AgentBehavior
|
||||
{
|
||||
public event Action OnMatch;
|
||||
public float2 TargetVelocity;
|
||||
private Thruster _thrust;
|
||||
private const float TargetThreshold = .1f;
|
||||
|
||||
private ItemManager _context;
|
||||
|
||||
public VelocityMatch(ItemManager context, Entity entity, ControllerData controllerData) : base(context, entity, controllerData)
|
||||
{
|
||||
_context = context;
|
||||
_thrust = Entity.GetBehavior<Thruster>();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
OnMatch = null;
|
||||
}
|
||||
|
||||
public override void Update(float delta)
|
||||
{
|
||||
// if (_thrust != null && _turning != null)
|
||||
// {
|
||||
// var deltaV = TargetVelocity - Entity.Velocity;
|
||||
// if(length(deltaV) < TargetThreshold)
|
||||
// OnMatch?.Invoke();
|
||||
// _turning.Axis = TurningInput(deltaV);
|
||||
// _thrust.Axis = ThrustInput(deltaV);
|
||||
// }
|
||||
}
|
||||
|
||||
public float2 MatchDistanceTime
|
||||
{
|
||||
get
|
||||
{
|
||||
// var velocity = length(Entity.Velocity);
|
||||
// var deltaV = TargetVelocity - Entity.Velocity;
|
||||
//
|
||||
// var stoppingTime = length(deltaV) / (_thrust.Thrust / Entity.Mass);
|
||||
// var stoppingDistance = stoppingTime * (velocity / 2);
|
||||
//
|
||||
// var angleDiff = Entity.Direction.AngleDiff(deltaV);
|
||||
// var turnaroundTime = angleDiff / (_turning.Torque / Entity.Mass);
|
||||
// var turnaroundDistance = turnaroundTime * velocity;
|
||||
//
|
||||
// return float2(stoppingDistance + turnaroundDistance, stoppingTime + turnaroundTime);
|
||||
return float2.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: df5185d5435658841878b6a8c9ff693b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -71,14 +71,6 @@ public interface IPopulationAssignment
|
|||
int AssignedPopulation { get; set; }
|
||||
}
|
||||
|
||||
public interface IController<T> where T: AgentTask
|
||||
{
|
||||
bool Available { get; }
|
||||
//TaskType TaskType { get; }
|
||||
Zone Zone { get; }
|
||||
void AssignTask(T task);
|
||||
}
|
||||
|
||||
[MessagePackObject,
|
||||
Union(0, typeof(FactoryPersistence)),
|
||||
JsonObject(MemberSerialization.OptIn),
|
||||
|
|
@ -101,8 +93,8 @@ public abstract class PersistentBehaviorData
|
|||
Union(10, typeof(VelocityConversionData)),
|
||||
Union(11, typeof(VelocityLimitData)),
|
||||
Union(12, typeof(FactoryData)),
|
||||
Union(13, typeof(PatrolControllerData)),
|
||||
Union(14, typeof(TowingControllerData)),
|
||||
// Union(13, typeof(PatrolControllerData)),
|
||||
// Union(14, typeof(TowingControllerData)),
|
||||
Union(15, typeof(CooldownData)),
|
||||
Union(16, typeof(HeatData)),
|
||||
// Union(17, typeof(HitscanData)),
|
||||
|
|
@ -113,12 +105,12 @@ public abstract class PersistentBehaviorData
|
|||
Union(22, typeof(VisibilityData)),
|
||||
Union(23, typeof(ThermotoggleData)),
|
||||
Union(24, typeof(EnergyDrawData)),
|
||||
Union(25, typeof(MiningControllerData)),
|
||||
// Union(25, typeof(MiningControllerData)),
|
||||
Union(26, typeof(MiningToolData)),
|
||||
Union(27, typeof(SurveyControllerData)),
|
||||
// Union(27, typeof(SurveyControllerData)),
|
||||
Union(28, typeof(ResourceScannerData)),
|
||||
Union(29, typeof(WanderControllerData)),
|
||||
Union(30, typeof(HaulingControllerData)),
|
||||
// Union(29, typeof(WanderControllerData)),
|
||||
// Union(30, typeof(HaulingControllerData)),
|
||||
Union(31, typeof(CapacitorData)),
|
||||
Union(32, typeof(CockpitData)),
|
||||
Union(33, typeof(HeatsinkData)),
|
||||
|
|
|
|||
|
|
@ -62,6 +62,15 @@ public class ChargedWeapon : InstantWeapon
|
|||
public float ChargeTime { get; protected set; }
|
||||
public float ChargeEnergy { get; protected set; }
|
||||
public float ChargeHeat { get; protected set; }
|
||||
|
||||
public override float DamagePerSecond => Damage * _data.ChargeFiringDamageMultiplier / (Cooldown + ChargeTime);
|
||||
public override float RangeDamagePerSecond(float range)
|
||||
{
|
||||
return Damage *
|
||||
_data.ChargeFiringDamageMultiplier *
|
||||
_data.DamageCurve.Evaluate(saturate(unlerp(MinRange, Range, range))) /
|
||||
(Cooldown + ChargeTime);
|
||||
}
|
||||
|
||||
public event Action OnStartCharging;
|
||||
public event Action OnStopCharging;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,12 @@ public class ConstantWeapon : Weapon, IProgressBehavior
|
|||
{
|
||||
get { return saturate(_reload); }
|
||||
}
|
||||
|
||||
public override float DamagePerSecond => Damage;
|
||||
public override float RangeDamagePerSecond(float range)
|
||||
{
|
||||
return Damage * _data.DamageCurve.Evaluate(saturate(unlerp(MinRange, Range, range)));
|
||||
}
|
||||
|
||||
public event Action OnReloadBegin;
|
||||
public event Action OnReloadComplete;
|
||||
|
|
|
|||
|
|
@ -1,257 +0,0 @@
|
|||
/* 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 MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
using UniRx;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
using float2 = Unity.Mathematics.float2;
|
||||
|
||||
[Union(0, typeof(TowingControllerData))]
|
||||
public abstract class ControllerData : BehaviorData
|
||||
{
|
||||
[InspectableField, JsonProperty("thrustSensitivity"), Key(1)]
|
||||
public float ThrustSensitivity = 1;
|
||||
|
||||
[InspectableField, JsonProperty("thrustSpecificity"), Key(2)]
|
||||
public float ThrustSpecificity = 8;
|
||||
|
||||
[InspectableField, JsonProperty("turningSensitivity"), Key(3)]
|
||||
public float TurningSensitivity = 1;
|
||||
|
||||
[InspectableField, JsonProperty("tangentSensitivity"), Key(4)]
|
||||
public float TangentSensitivity = 4;
|
||||
|
||||
[InspectableField, JsonProperty("targetDistance"), Key(5)]
|
||||
public float TargetDistance = 10;
|
||||
}
|
||||
|
||||
public abstract class ControllerBase<T> : IBehavior, IController<T>, IInitializableBehavior where T : AgentTask
|
||||
{
|
||||
protected Entity HomeEntity => (Entity as Ship)?.HomeEntity;
|
||||
public bool Available => _spaceworthy && Task == null;
|
||||
//public abstract TaskType TaskType { get; }
|
||||
public Zone Zone => Entity.Zone;
|
||||
public BehaviorData Data => _controllerData;
|
||||
|
||||
protected ItemManager ItemManager { get; }
|
||||
protected Entity Entity { get; }
|
||||
|
||||
protected Locomotion Locomotion;
|
||||
protected VelocityMatch VelocityMatch;
|
||||
protected Func<float2> TargetPosition;
|
||||
protected Func<float2> TargetVelocity;
|
||||
protected bool MatchVelocity;
|
||||
// protected List<ZoneDefinition> Path;
|
||||
protected T Task;
|
||||
protected bool Moving;
|
||||
protected bool Waiting;
|
||||
|
||||
private ControllerData _controllerData;
|
||||
private MovementPhase _movementPhase;
|
||||
private Action _onFinishMoving;
|
||||
private bool _spaceworthy;
|
||||
private float _waitTime;
|
||||
private Action _onFinishWaiting;
|
||||
|
||||
public ControllerBase(ItemManager itemManager, ControllerData data, Entity entity)
|
||||
{
|
||||
ItemManager = itemManager;
|
||||
Entity = entity;
|
||||
_controllerData = data;
|
||||
CheckSpaceworthiness();
|
||||
entity.Equipment.ObserveAdd().Subscribe(added => CheckSpaceworthiness());
|
||||
}
|
||||
|
||||
private void CheckSpaceworthiness()
|
||||
{
|
||||
_spaceworthy = Entity.GetBehavior<Thruster>() != null && Entity.GetBehavior<Reactor>() != null;
|
||||
if(_spaceworthy)
|
||||
CreateBehaviors();
|
||||
}
|
||||
|
||||
public void CreateBehaviors()
|
||||
{
|
||||
Locomotion = new Locomotion(ItemManager, Entity, _controllerData);
|
||||
VelocityMatch = new VelocityMatch(ItemManager, Entity, _controllerData);
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
CreateBehaviors();
|
||||
// _context.CorporationControllers[_entity.Corporation].Add(this);
|
||||
}
|
||||
|
||||
public void AssignTask(T task)
|
||||
{
|
||||
Task = task;
|
||||
Moving = false;
|
||||
}
|
||||
|
||||
public bool Execute(float delta)
|
||||
{
|
||||
if (Available)
|
||||
{
|
||||
// No task is assigned and we're at home, do nothing!
|
||||
if (Entity.Parent == HomeEntity)
|
||||
return false;
|
||||
|
||||
// No task is assigned, but we're not home, go home!
|
||||
if (!Moving)
|
||||
{
|
||||
GoHome();
|
||||
}
|
||||
}
|
||||
|
||||
if (Waiting)
|
||||
{
|
||||
_waitTime -= delta;
|
||||
if (_waitTime < 0)
|
||||
{
|
||||
Waiting = false;
|
||||
_onFinishWaiting?.Invoke();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Moving)
|
||||
{
|
||||
if(Entity.Parent!=null)
|
||||
Entity.RemoveParent();
|
||||
|
||||
var targetPosition = TargetPosition();
|
||||
var distance = length(targetPosition - Entity.Position.xz);
|
||||
if (MatchVelocity)
|
||||
{
|
||||
var targetVelocity = TargetVelocity();
|
||||
VelocityMatch.TargetVelocity = targetVelocity;
|
||||
if (_movementPhase == MovementPhase.Locomotion)
|
||||
{
|
||||
var matchDistanceTime = VelocityMatch.MatchDistanceTime;
|
||||
Locomotion.Objective = targetPosition + targetVelocity * matchDistanceTime.y;
|
||||
Locomotion.Update(delta);
|
||||
|
||||
if (distance < matchDistanceTime.x)
|
||||
{
|
||||
_movementPhase = MovementPhase.Slowdown;
|
||||
//_context.Log($"Controller {_entity.Name} has entered slowdown phase.");
|
||||
VelocityMatch.Clear();
|
||||
VelocityMatch.OnMatch += () =>
|
||||
{
|
||||
Moving = false;
|
||||
_onFinishMoving?.Invoke();
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VelocityMatch.TargetVelocity = targetVelocity;
|
||||
VelocityMatch.Update(delta);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Locomotion.Objective = TargetPosition();
|
||||
Locomotion.Update(delta);
|
||||
if (distance < _controllerData.TargetDistance)
|
||||
{
|
||||
Moving = false;
|
||||
_onFinishMoving();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void FinishTask()
|
||||
{
|
||||
if (Task == null)
|
||||
return;
|
||||
|
||||
Task = null;
|
||||
}
|
||||
|
||||
public void GoHome(Action onFinish = null)
|
||||
{
|
||||
MoveTo(HomeEntity, true, () =>
|
||||
{
|
||||
Entity.SetParent(HomeEntity);
|
||||
onFinish?.Invoke();
|
||||
});
|
||||
// else MoveTo(homeEntity.Zone.Data.ID, () => MoveTo(homeEntity, true, () =>
|
||||
// {
|
||||
// _entity.SetParent(homeEntity);
|
||||
// onFinish?.Invoke();
|
||||
// }));
|
||||
}
|
||||
|
||||
public void Wait(float time, Action onFinish = null)
|
||||
{
|
||||
_waitTime = time;
|
||||
Waiting = true;
|
||||
_onFinishWaiting = onFinish;
|
||||
}
|
||||
|
||||
public void MoveTo(Entity entity, bool matchVelocity = true, Action onFinish = null)
|
||||
{
|
||||
TargetPosition = () => entity.Position.xz;
|
||||
TargetVelocity = () => entity.Velocity;
|
||||
MatchVelocity = matchVelocity;
|
||||
_movementPhase = MovementPhase.Locomotion;
|
||||
Moving = true;
|
||||
_onFinishMoving = onFinish;
|
||||
}
|
||||
|
||||
public void MoveTo(float2 position, bool matchVelocity = true, Action onFinish = null)
|
||||
{
|
||||
TargetPosition = () => position;
|
||||
TargetVelocity = () => float2.zero;
|
||||
MatchVelocity = matchVelocity;
|
||||
_movementPhase = MovementPhase.Locomotion;
|
||||
Moving = true;
|
||||
_onFinishMoving = onFinish;
|
||||
}
|
||||
|
||||
public void MoveTo(Func<float2> position, Func<float2> velocity, Action onFinish = null)
|
||||
{
|
||||
TargetPosition = position;
|
||||
TargetVelocity = velocity;
|
||||
MatchVelocity = true;
|
||||
_movementPhase = MovementPhase.Locomotion;
|
||||
Moving = true;
|
||||
_onFinishMoving = onFinish;
|
||||
}
|
||||
|
||||
// public void MoveTo(Guid zone, Action onFinish = null)
|
||||
// {
|
||||
// var path = _context.FindPath(_context.GalaxyZones[Zone.Data.ID], _context.GalaxyZones[zone]);
|
||||
//
|
||||
// void OnNextZone()
|
||||
// {
|
||||
// path.RemoveAt(0);
|
||||
// if (path.Count > 0)
|
||||
// {
|
||||
// MoveTo(Zone.WormholePosition(Path[0]), false, OnNextZone);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// onFinish?.Invoke();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// OnNextZone();
|
||||
// }
|
||||
}
|
||||
|
||||
public enum MovementPhase
|
||||
{
|
||||
Locomotion,
|
||||
Slowdown
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0bd22c9213b660e4d845f7a751f18848
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -2,146 +2,146 @@
|
|||
* 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.Linq;
|
||||
using MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship), Order(-100)]
|
||||
public class HaulingControllerData : ControllerData
|
||||
{
|
||||
[InspectableField, JsonProperty("targetDistance"), Key(6)]
|
||||
public float DockTime = 2;
|
||||
public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
|
||||
{
|
||||
return new HaulingController(context, this, entity, item);
|
||||
}
|
||||
}
|
||||
|
||||
public class HaulingController : ControllerBase<HaulingTask>, IBehavior, IPersistentBehavior
|
||||
{
|
||||
private HaulingControllerData _data;
|
||||
private EquippedItem Item { get; }
|
||||
|
||||
private bool _taskStarted;
|
||||
private int _itemsDelivered;
|
||||
private int _itemsCarried;
|
||||
private SimpleCommodity _simpleCommodityDelivery;
|
||||
private List<CraftedItemInstance> _craftedItemDelivery = new List<CraftedItemInstance>();
|
||||
|
||||
public HaulingController(ItemManager itemManager, HaulingControllerData data, Entity entity, EquippedItem item) : base(itemManager, data, entity)
|
||||
{
|
||||
_data = data;
|
||||
Item = item;
|
||||
}
|
||||
|
||||
public new bool Execute(float delta)
|
||||
{
|
||||
if (Task != null)
|
||||
{
|
||||
if (!_taskStarted)
|
||||
{
|
||||
MoveTo(Task.Origin, true, OnPickup);
|
||||
//MoveTo(haulingTask.Zone, OnOriginZoneArrival);
|
||||
_taskStarted = true;
|
||||
}
|
||||
}
|
||||
return base.Execute(delta);
|
||||
}
|
||||
|
||||
// void OnOriginZoneArrival()
|
||||
// {
|
||||
// var haulingTask = _context.ItemData.Get<HaulingTask>(Task);
|
||||
//
|
||||
// _entity.SetMessage("Entering pickup phase.");
|
||||
//
|
||||
// MoveTo(_context.ItemData.Get<Entity>(haulingTask.Origin), true, OnPickup);
|
||||
// }
|
||||
|
||||
void OnPickup()
|
||||
{
|
||||
Entity.SetParent(Task.Origin);
|
||||
|
||||
_itemsCarried = Task.Origin.TryTransferItems(Entity, Task.ItemType, Task.Quantity - _itemsDelivered);
|
||||
|
||||
if (_itemsCarried == 0)
|
||||
{
|
||||
FinishTask();
|
||||
return;
|
||||
}
|
||||
|
||||
Wait(_data.DockTime, OnItemObtained);
|
||||
}
|
||||
|
||||
void OnItemObtained()
|
||||
{
|
||||
Entity.SetMessage("Entering delivery phase.");
|
||||
|
||||
MoveTo(Task.Target, true, OnDelivery);
|
||||
//MoveTo(target.Zone.Data.ID, OnTargetZoneArrival);
|
||||
}
|
||||
|
||||
// void OnTargetZoneArrival()
|
||||
// {
|
||||
// var haulingTask = _context.ItemData.Get<HaulingTask>(Task);
|
||||
//
|
||||
// MoveTo(_context.ItemData.Get<Entity>(haulingTask.Target), true, OnDelivery);
|
||||
// }
|
||||
|
||||
void OnDelivery()
|
||||
{
|
||||
Entity.SetParent(Task.Target);
|
||||
|
||||
var itemsDelivered = Entity.TryTransferItems(Task.Target, Task.ItemType, _itemsCarried);
|
||||
_itemsCarried -= itemsDelivered;
|
||||
_itemsDelivered += itemsDelivered;
|
||||
|
||||
Wait(_data.DockTime, () =>
|
||||
{
|
||||
// We were unable to transfer all onboard items to target entity, cargo is probably full. Bring back the surplus and end the mission
|
||||
if(_itemsCarried > 0)
|
||||
MoveTo(Task.Origin, true, ReturnSurplusToOrigin);
|
||||
// We have delivered the target quantity of items, end the mission
|
||||
else if(_itemsDelivered >= Task.Quantity)
|
||||
FinishTask();
|
||||
// We aren't done yet. Resetting the task will make us go for another delivery run
|
||||
else
|
||||
_taskStarted = false;
|
||||
});
|
||||
}
|
||||
|
||||
void ReturnSurplusToOrigin()
|
||||
{
|
||||
Entity.SetParent(Task.Origin);
|
||||
|
||||
Entity.TryTransferItems(Task.Origin, Task.ItemType, _itemsCarried);
|
||||
|
||||
Wait(_data.DockTime, OnItemObtained);
|
||||
|
||||
FinishTask();
|
||||
}
|
||||
|
||||
public PersistentBehaviorData Store()
|
||||
{
|
||||
return new HaulingControllerPersistence
|
||||
{
|
||||
Task = Task
|
||||
};
|
||||
}
|
||||
|
||||
public void Restore(PersistentBehaviorData data)
|
||||
{
|
||||
var towingControllerPersistence = data as HaulingControllerPersistence;
|
||||
Task = towingControllerPersistence.Task;
|
||||
}
|
||||
}
|
||||
|
||||
public class HaulingControllerPersistence : PersistentBehaviorData
|
||||
{
|
||||
[JsonProperty("task"), Key(0)]
|
||||
public HaulingTask Task;
|
||||
}
|
||||
// using System;
|
||||
// using System.Collections;
|
||||
// using System.Collections.Generic;
|
||||
// using System.Linq;
|
||||
// using MessagePack;
|
||||
// using Newtonsoft.Json;
|
||||
// using Unity.Mathematics;
|
||||
// using static Unity.Mathematics.math;
|
||||
//
|
||||
// [MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship), Order(-100)]
|
||||
// public class HaulingControllerData : ControllerData
|
||||
// {
|
||||
// [InspectableField, JsonProperty("targetDistance"), Key(6)]
|
||||
// public float DockTime = 2;
|
||||
// public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
|
||||
// {
|
||||
// return new HaulingController(context, this, entity, item);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public class HaulingController : ControllerBase<HaulingTask>, IBehavior, IPersistentBehavior
|
||||
// {
|
||||
// private HaulingControllerData _data;
|
||||
// private EquippedItem Item { get; }
|
||||
//
|
||||
// private bool _taskStarted;
|
||||
// private int _itemsDelivered;
|
||||
// private int _itemsCarried;
|
||||
// private SimpleCommodity _simpleCommodityDelivery;
|
||||
// private List<CraftedItemInstance> _craftedItemDelivery = new List<CraftedItemInstance>();
|
||||
//
|
||||
// public HaulingController(ItemManager itemManager, HaulingControllerData data, Entity entity, EquippedItem item) : base(itemManager, data, entity)
|
||||
// {
|
||||
// _data = data;
|
||||
// Item = item;
|
||||
// }
|
||||
//
|
||||
// public new bool Execute(float delta)
|
||||
// {
|
||||
// if (Task != null)
|
||||
// {
|
||||
// if (!_taskStarted)
|
||||
// {
|
||||
// MoveTo(Task.Origin, true, OnPickup);
|
||||
// //MoveTo(haulingTask.Zone, OnOriginZoneArrival);
|
||||
// _taskStarted = true;
|
||||
// }
|
||||
// }
|
||||
// return base.Execute(delta);
|
||||
// }
|
||||
//
|
||||
// // void OnOriginZoneArrival()
|
||||
// // {
|
||||
// // var haulingTask = _context.ItemData.Get<HaulingTask>(Task);
|
||||
// //
|
||||
// // _entity.SetMessage("Entering pickup phase.");
|
||||
// //
|
||||
// // MoveTo(_context.ItemData.Get<Entity>(haulingTask.Origin), true, OnPickup);
|
||||
// // }
|
||||
//
|
||||
// void OnPickup()
|
||||
// {
|
||||
// Entity.SetParent(Task.Origin);
|
||||
//
|
||||
// _itemsCarried = Task.Origin.TryTransferItems(Entity, Task.ItemType, Task.Quantity - _itemsDelivered);
|
||||
//
|
||||
// if (_itemsCarried == 0)
|
||||
// {
|
||||
// FinishTask();
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// Wait(_data.DockTime, OnItemObtained);
|
||||
// }
|
||||
//
|
||||
// void OnItemObtained()
|
||||
// {
|
||||
// Entity.SetMessage("Entering delivery phase.");
|
||||
//
|
||||
// MoveTo(Task.Target, true, OnDelivery);
|
||||
// //MoveTo(target.Zone.Data.ID, OnTargetZoneArrival);
|
||||
// }
|
||||
//
|
||||
// // void OnTargetZoneArrival()
|
||||
// // {
|
||||
// // var haulingTask = _context.ItemData.Get<HaulingTask>(Task);
|
||||
// //
|
||||
// // MoveTo(_context.ItemData.Get<Entity>(haulingTask.Target), true, OnDelivery);
|
||||
// // }
|
||||
//
|
||||
// void OnDelivery()
|
||||
// {
|
||||
// Entity.SetParent(Task.Target);
|
||||
//
|
||||
// var itemsDelivered = Entity.TryTransferItems(Task.Target, Task.ItemType, _itemsCarried);
|
||||
// _itemsCarried -= itemsDelivered;
|
||||
// _itemsDelivered += itemsDelivered;
|
||||
//
|
||||
// Wait(_data.DockTime, () =>
|
||||
// {
|
||||
// // We were unable to transfer all onboard items to target entity, cargo is probably full. Bring back the surplus and end the mission
|
||||
// if(_itemsCarried > 0)
|
||||
// MoveTo(Task.Origin, true, ReturnSurplusToOrigin);
|
||||
// // We have delivered the target quantity of items, end the mission
|
||||
// else if(_itemsDelivered >= Task.Quantity)
|
||||
// FinishTask();
|
||||
// // We aren't done yet. Resetting the task will make us go for another delivery run
|
||||
// else
|
||||
// _taskStarted = false;
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// void ReturnSurplusToOrigin()
|
||||
// {
|
||||
// Entity.SetParent(Task.Origin);
|
||||
//
|
||||
// Entity.TryTransferItems(Task.Origin, Task.ItemType, _itemsCarried);
|
||||
//
|
||||
// Wait(_data.DockTime, OnItemObtained);
|
||||
//
|
||||
// FinishTask();
|
||||
// }
|
||||
//
|
||||
// public PersistentBehaviorData Store()
|
||||
// {
|
||||
// return new HaulingControllerPersistence
|
||||
// {
|
||||
// Task = Task
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// public void Restore(PersistentBehaviorData data)
|
||||
// {
|
||||
// var towingControllerPersistence = data as HaulingControllerPersistence;
|
||||
// Task = towingControllerPersistence.Task;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public class HaulingControllerPersistence : PersistentBehaviorData
|
||||
// {
|
||||
// [JsonProperty("task"), Key(0)]
|
||||
// public HaulingTask Task;
|
||||
// }
|
||||
|
|
@ -37,10 +37,20 @@ public class InstantWeapon : Weapon, IProgressBehavior
|
|||
protected float _cooldown; // Normalized
|
||||
private int _ammo = 0;
|
||||
protected bool _coolingDown;
|
||||
|
||||
|
||||
public float BurstCount { get; protected set; }
|
||||
public float BurstTime { get; protected set; }
|
||||
public float Cooldown { get; protected set; }
|
||||
public virtual bool CanFire
|
||||
{
|
||||
get => !_coolingDown;
|
||||
}
|
||||
|
||||
public override float DamagePerSecond => Damage / Cooldown;
|
||||
public override float RangeDamagePerSecond(float range)
|
||||
{
|
||||
return Damage * _data.DamageCurve.Evaluate(saturate(unlerp(MinRange, Range, range))) / Cooldown;
|
||||
}
|
||||
|
||||
public override int Ammo
|
||||
{
|
||||
|
|
@ -126,11 +136,11 @@ public class InstantWeapon : Weapon, IProgressBehavior
|
|||
base.Execute(delta);
|
||||
if (_coolingDown)
|
||||
{
|
||||
_cooldown -= delta / (_ammo == 0 ? _data.ReloadTime : Cooldown);
|
||||
_cooldown -= delta / (_data.AmmoType != Guid.Empty && _ammo == 0 ? _data.ReloadTime : Cooldown);
|
||||
if (_cooldown < 0)
|
||||
{
|
||||
_coolingDown = false;
|
||||
if (_ammo == 0)
|
||||
if (_data.AmmoType != Guid.Empty && _ammo == 0)
|
||||
{
|
||||
_ammo = _data.MagazineSize;
|
||||
OnReloadComplete?.Invoke();
|
||||
|
|
@ -159,7 +169,7 @@ public class InstantWeapon : Weapon, IProgressBehavior
|
|||
|
||||
public override void Activate()
|
||||
{
|
||||
if(!_coolingDown)
|
||||
if(CanFire)
|
||||
Trigger();
|
||||
base.Activate();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ public class LockWeapon : InstantWeapon
|
|||
|
||||
public override float Progress => saturate(_cooldown > 0 ? _cooldown : _lock);
|
||||
|
||||
public override bool CanFire => base.CanFire && _lock > .99f && Entity.TargetRange > MinRange && Entity.TargetRange < Range;
|
||||
|
||||
public float Lock
|
||||
{
|
||||
get => saturate(_lock);
|
||||
|
|
@ -86,13 +88,5 @@ public class LockWeapon : InstantWeapon
|
|||
|
||||
return base.Execute(delta);
|
||||
}
|
||||
|
||||
public override void Activate()
|
||||
{
|
||||
if(_lock > .99f)
|
||||
{
|
||||
base.Activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,131 +11,131 @@ using Newtonsoft.Json;
|
|||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship), Order(-100)]
|
||||
public class MiningControllerData : ControllerData
|
||||
{
|
||||
public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
|
||||
{
|
||||
return new MiningController(context, this, entity, item);
|
||||
}
|
||||
}
|
||||
|
||||
public class MiningController : ControllerBase<Mining>, IBehavior, IPersistentBehavior, IInitializableBehavior
|
||||
{
|
||||
|
||||
private MiningControllerData _data;
|
||||
private EquippedItem Item { get; }
|
||||
private bool _taskStarted;
|
||||
private int _asteroid = -1;
|
||||
private MiningTool _miningTool;
|
||||
private Switch _toolSwitch;
|
||||
|
||||
public MiningController(ItemManager itemManager, MiningControllerData data, Entity entity, EquippedItem item) : base(itemManager, data, entity)
|
||||
{
|
||||
_data = data;
|
||||
Item = item;
|
||||
}
|
||||
|
||||
public new void Initialize()
|
||||
{
|
||||
// _miningTool = Entity.GetBehavior<MiningTool>();
|
||||
// _toolSwitch = Entity.GetSwitch<MiningTool>();
|
||||
base.Initialize();
|
||||
}
|
||||
|
||||
public new bool Execute(float delta)
|
||||
{
|
||||
// if (Task != null)
|
||||
// {
|
||||
// if (!_taskStarted)
|
||||
// {
|
||||
// NextAsteroid();
|
||||
// _taskStarted = true;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (!Moving)
|
||||
// {
|
||||
// if (_entity.OccupiedCapacity < _entity.Capacity - 1)
|
||||
// {
|
||||
// var asteroidTransform = Zone.GetAsteroidTransform(Task.Asteroids, _asteroid);
|
||||
// if (length(_entity.Position - asteroidTransform.xy) - asteroidTransform.w > _miningTool.Range)
|
||||
// {
|
||||
// _entity.SetMessage("Moving to target asteroid.");
|
||||
// MoveTo(() => Zone.GetAsteroidTransform(Task.Asteroids, _asteroid).xy,
|
||||
// () => Zone.GetAsteroidVelocity(Task.Asteroids, _asteroid));
|
||||
// _toolSwitch.Activated = false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (Zone.AsteroidExists(Task.Asteroids, _asteroid))
|
||||
// {
|
||||
// _miningTool.AsteroidBelt = Task.Asteroids;
|
||||
// _miningTool.Asteroid = _asteroid;
|
||||
// _toolSwitch.Activated = true;
|
||||
// Aim.Objective = Zone.GetAsteroidTransform(Task.Asteroids, _asteroid).xy;
|
||||
// Aim.Update(delta);
|
||||
// }
|
||||
// else NextAsteroid();
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// _entity.SetMessage("Out of cargo space. Returning home to offload cargo.");
|
||||
// GoHome(OnArriveHome);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return base.Execute(delta);
|
||||
}
|
||||
|
||||
// private void OnArriveHome()
|
||||
// {
|
||||
// var homeEntity = _context.ItemData.Get<Entity>(HomeEntity);
|
||||
// foreach (var item in _entity.Cargo
|
||||
// .Select(id => _context.ItemData.Get<ItemInstance>(id))
|
||||
// .Where(item => item is SimpleCommodity)
|
||||
// .Cast<SimpleCommodity>()
|
||||
// .ToArray())
|
||||
// {
|
||||
// int quantity = min((int) ((homeEntity.Capacity - homeEntity.OccupiedCapacity) / _context.GetData(item).Size), item.Quantity);
|
||||
// var newItem = _entity.RemoveCargo(item, quantity);
|
||||
// homeEntity.AddCargo(newItem);
|
||||
//
|
||||
// if (quantity < item.Quantity)
|
||||
// {
|
||||
// homeEntity.SetMessage("Colony is out of cargo space. Closing Mining Task.");
|
||||
// FinishTask();
|
||||
// _taskStarted = false;
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
private void NextAsteroid()
|
||||
{
|
||||
_asteroid = Zone.NearestAsteroid(Task.Asteroids, Entity.Position.xz);
|
||||
Entity.SetMessage("Selecting new asteroid.");
|
||||
}
|
||||
|
||||
public PersistentBehaviorData Store()
|
||||
{
|
||||
return new MiningControllerPersistence
|
||||
{
|
||||
Task = Task
|
||||
};
|
||||
}
|
||||
|
||||
public void Restore(PersistentBehaviorData data)
|
||||
{
|
||||
var miningControllerPersistence = data as MiningControllerPersistence;
|
||||
Task = miningControllerPersistence.Task;
|
||||
}
|
||||
}
|
||||
|
||||
public class MiningControllerPersistence : PersistentBehaviorData
|
||||
{
|
||||
[JsonProperty("task"), Key(0)]
|
||||
public Mining Task;
|
||||
}
|
||||
// [MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship), Order(-100)]
|
||||
// public class MiningControllerData : ControllerData
|
||||
// {
|
||||
// public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
|
||||
// {
|
||||
// return new MiningController(context, this, entity, item);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public class MiningController : ControllerBase<Mining>, IBehavior, IPersistentBehavior, IInitializableBehavior
|
||||
// {
|
||||
//
|
||||
// private MiningControllerData _data;
|
||||
// private EquippedItem Item { get; }
|
||||
// private bool _taskStarted;
|
||||
// private int _asteroid = -1;
|
||||
// private MiningTool _miningTool;
|
||||
// private Switch _toolSwitch;
|
||||
//
|
||||
// public MiningController(ItemManager itemManager, MiningControllerData data, Entity entity, EquippedItem item) : base(itemManager, data, entity)
|
||||
// {
|
||||
// _data = data;
|
||||
// Item = item;
|
||||
// }
|
||||
//
|
||||
// public new void Initialize()
|
||||
// {
|
||||
// // _miningTool = Entity.GetBehavior<MiningTool>();
|
||||
// // _toolSwitch = Entity.GetSwitch<MiningTool>();
|
||||
// base.Initialize();
|
||||
// }
|
||||
//
|
||||
// public new bool Execute(float delta)
|
||||
// {
|
||||
// // if (Task != null)
|
||||
// // {
|
||||
// // if (!_taskStarted)
|
||||
// // {
|
||||
// // NextAsteroid();
|
||||
// // _taskStarted = true;
|
||||
// // }
|
||||
// // else
|
||||
// // {
|
||||
// // if (!Moving)
|
||||
// // {
|
||||
// // if (_entity.OccupiedCapacity < _entity.Capacity - 1)
|
||||
// // {
|
||||
// // var asteroidTransform = Zone.GetAsteroidTransform(Task.Asteroids, _asteroid);
|
||||
// // if (length(_entity.Position - asteroidTransform.xy) - asteroidTransform.w > _miningTool.Range)
|
||||
// // {
|
||||
// // _entity.SetMessage("Moving to target asteroid.");
|
||||
// // MoveTo(() => Zone.GetAsteroidTransform(Task.Asteroids, _asteroid).xy,
|
||||
// // () => Zone.GetAsteroidVelocity(Task.Asteroids, _asteroid));
|
||||
// // _toolSwitch.Activated = false;
|
||||
// // }
|
||||
// // else
|
||||
// // {
|
||||
// // if (Zone.AsteroidExists(Task.Asteroids, _asteroid))
|
||||
// // {
|
||||
// // _miningTool.AsteroidBelt = Task.Asteroids;
|
||||
// // _miningTool.Asteroid = _asteroid;
|
||||
// // _toolSwitch.Activated = true;
|
||||
// // Aim.Objective = Zone.GetAsteroidTransform(Task.Asteroids, _asteroid).xy;
|
||||
// // Aim.Update(delta);
|
||||
// // }
|
||||
// // else NextAsteroid();
|
||||
// // }
|
||||
// // }
|
||||
// // else
|
||||
// // {
|
||||
// // _entity.SetMessage("Out of cargo space. Returning home to offload cargo.");
|
||||
// // GoHome(OnArriveHome);
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
// return base.Execute(delta);
|
||||
// }
|
||||
//
|
||||
// // private void OnArriveHome()
|
||||
// // {
|
||||
// // var homeEntity = _context.ItemData.Get<Entity>(HomeEntity);
|
||||
// // foreach (var item in _entity.Cargo
|
||||
// // .Select(id => _context.ItemData.Get<ItemInstance>(id))
|
||||
// // .Where(item => item is SimpleCommodity)
|
||||
// // .Cast<SimpleCommodity>()
|
||||
// // .ToArray())
|
||||
// // {
|
||||
// // int quantity = min((int) ((homeEntity.Capacity - homeEntity.OccupiedCapacity) / _context.GetData(item).Size), item.Quantity);
|
||||
// // var newItem = _entity.RemoveCargo(item, quantity);
|
||||
// // homeEntity.AddCargo(newItem);
|
||||
// //
|
||||
// // if (quantity < item.Quantity)
|
||||
// // {
|
||||
// // homeEntity.SetMessage("Colony is out of cargo space. Closing Mining Task.");
|
||||
// // FinishTask();
|
||||
// // _taskStarted = false;
|
||||
// // return;
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
//
|
||||
// private void NextAsteroid()
|
||||
// {
|
||||
// _asteroid = Zone.NearestAsteroid(Task.Asteroids, Entity.Position.xz);
|
||||
// Entity.SetMessage("Selecting new asteroid.");
|
||||
// }
|
||||
//
|
||||
// public PersistentBehaviorData Store()
|
||||
// {
|
||||
// return new MiningControllerPersistence
|
||||
// {
|
||||
// Task = Task
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// public void Restore(PersistentBehaviorData data)
|
||||
// {
|
||||
// var miningControllerPersistence = data as MiningControllerPersistence;
|
||||
// Task = miningControllerPersistence.Task;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public class MiningControllerPersistence : PersistentBehaviorData
|
||||
// {
|
||||
// [JsonProperty("task"), Key(0)]
|
||||
// public Mining Task;
|
||||
// }
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/* 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.Linq;
|
||||
using MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship), Order(-100)]
|
||||
public class PatrolControllerData : ControllerData
|
||||
{
|
||||
public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
|
||||
{
|
||||
return new PatrolController(context, this, entity, item);
|
||||
}
|
||||
}
|
||||
|
||||
public class PatrolController : IBehavior, IInitializableBehavior
|
||||
{
|
||||
public BehaviorData Data => _data;
|
||||
|
||||
private PatrolControllerData _data;
|
||||
private ItemManager Context { get; }
|
||||
private Entity Entity { get; }
|
||||
private EquippedItem Item { get; }
|
||||
private Locomotion _locomotion;
|
||||
private Guid _targetOrbit;
|
||||
|
||||
public PatrolController(ItemManager context, PatrolControllerData data, Entity entity, EquippedItem item)
|
||||
{
|
||||
Context = context;
|
||||
_data = data;
|
||||
Entity = entity;
|
||||
Item = item;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_locomotion = new Locomotion(Context, Entity, _data);
|
||||
RandomTarget();
|
||||
}
|
||||
|
||||
public bool Execute(float delta)
|
||||
{
|
||||
_locomotion.Objective = Entity.Zone.GetOrbitPosition(_targetOrbit);
|
||||
_locomotion.Update(delta);
|
||||
|
||||
if(length(Entity.Position.xz - _locomotion.Objective) < _data.TargetDistance)
|
||||
RandomTarget();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void RandomTarget()
|
||||
{
|
||||
_targetOrbit = Entity.Zone.Planets.Keys.ToArray()[Context.Random.NextInt(Entity.Zone.Planets.Count)];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cc2d16773614011488d30e38edf7c3bb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -13,7 +13,7 @@ public class SensorData : BehaviorData
|
|||
[InspectableField, JsonProperty("sensitivity"), Key(3), RuntimeInspectable]
|
||||
public PerformanceStat Sensitivity = new PerformanceStat();
|
||||
|
||||
[InspectableField, JsonProperty("sensitivityCurve"), Key(4), RuntimeInspectable]
|
||||
[InspectableAnimationCurve, JsonProperty("sensitivityCurve"), Key(4), RuntimeInspectable]
|
||||
public float4[] SensitivityCurve;
|
||||
|
||||
public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
|
||||
|
|
@ -44,19 +44,28 @@ public class Sensor : IBehavior
|
|||
{
|
||||
// TODO: Handle Active Detection / Visibility From Reflected Radiance
|
||||
var hardpoint = Entity.Hardpoints[Item.Position.x, Item.Position.y];
|
||||
var forward = Entity.HardpointTransforms.ContainsKey(hardpoint) ?
|
||||
var forward = hardpoint != null && Entity.HardpointTransforms.ContainsKey(hardpoint) ?
|
||||
normalize(Entity.HardpointTransforms[hardpoint].direction.xz) :
|
||||
Entity.Direction;
|
||||
foreach (var entity in Entity.Zone.Entities)
|
||||
{
|
||||
var diff = entity.Position.xz - Entity.Position.xz;
|
||||
var angle = acos(dot(forward, normalize(diff)));
|
||||
var dist = length(diff);
|
||||
Entity.EntityInfoGathered[entity] +=
|
||||
entity.Visibility *
|
||||
Context.Evaluate(_data.Sensitivity, Item.EquippableItem, Entity) *
|
||||
_data.SensitivityCurve.Evaluate(angle / PI) *
|
||||
delta / dist;
|
||||
{
|
||||
if(entity != Entity)
|
||||
{
|
||||
var diff = entity.Position.xz - Entity.Position.xz;
|
||||
var angle = acos(dot(forward, normalize(diff)));
|
||||
var dist = length(diff);
|
||||
float previous;
|
||||
Entity.EntityInfoGathered.TryGetValue(entity, out previous);
|
||||
var next = saturate(
|
||||
previous +
|
||||
entity.Visibility *
|
||||
Context.Evaluate(_data.Sensitivity, Item.EquippableItem, Entity) *
|
||||
_data.SensitivityCurve.Evaluate(angle / PI) *
|
||||
delta / dist);
|
||||
next *= 1 - Context.GameplaySettings.TargetInfoDecay * delta;
|
||||
//Context.Log($"{entity.Name} visibility {(int)(previous * 100)}% -> {(int)(next * 100)}%");
|
||||
Entity.EntityInfoGathered[entity] = next;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
// var ship = Hardpoint.Ship.Ship.transform;
|
||||
|
|
|
|||
|
|
@ -12,144 +12,144 @@ using RethinkDb.Driver.Ast;
|
|||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship), Order(-100)]
|
||||
public class SurveyControllerData : ControllerData
|
||||
{
|
||||
public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
|
||||
{
|
||||
return new SurveyController(context, this, entity, item);
|
||||
}
|
||||
}
|
||||
|
||||
public class SurveyController : ControllerBase<Survey>, IBehavior, IPersistentBehavior, IInitializableBehavior
|
||||
{
|
||||
private EquippedItem Item { get; }
|
||||
|
||||
private SurveyControllerData _data;
|
||||
private bool _taskStarted;
|
||||
private ResourceScanner _scanningTool;
|
||||
private Switch _toolSwitch;
|
||||
private Guid _targetPlanet;
|
||||
private int _asteroid = -1;
|
||||
|
||||
public SurveyController(ItemManager itemManager, SurveyControllerData data, Entity entity, EquippedItem item) : base(itemManager, data, entity)
|
||||
{
|
||||
_data = data;
|
||||
Item = item;
|
||||
}
|
||||
|
||||
public new void Initialize()
|
||||
{
|
||||
_scanningTool = Entity.GetBehavior<ResourceScanner>();
|
||||
// _toolSwitch = Entity.GetSwitch<ResourceScanner>();
|
||||
base.Initialize();
|
||||
}
|
||||
|
||||
public new bool Execute(float delta)
|
||||
{
|
||||
// var corporation = _context.ItemData.Get<Corporation>(_entity.Corporation);
|
||||
// if (surveyTask != null)
|
||||
// {
|
||||
// if (!_taskStarted)
|
||||
// {
|
||||
// if (surveyTask.Planets.Any())
|
||||
// {
|
||||
// _entity.SetMessage("Moving to survey target.");
|
||||
// NextPlanet();
|
||||
// _scanningTool.ScanTarget = _targetPlanet;
|
||||
// _scanningTool.Asteroid = _asteroid;
|
||||
// if (!corporation.PlanetSurveyFloor.ContainsKey(_targetPlanet) ||
|
||||
// corporation.PlanetSurveyFloor[_targetPlanet] + .5f < _scanningTool.MinimumDensity)
|
||||
// {
|
||||
// var planetData = _context.ItemData.Get<BodyData>(_targetPlanet);
|
||||
// MoveTo(() =>
|
||||
// {
|
||||
// var target = GetPosition(planetData, _asteroid);
|
||||
// var targetToUs = _entity.Position - target;
|
||||
// return target + normalize(targetToUs) * _scanningTool.Range / 2;
|
||||
// },
|
||||
// () => GetVelocity(planetData, _asteroid),
|
||||
// () => _entity.SetMessage("Arrived at target. Scanning for resources."));
|
||||
// _taskStarted = true;
|
||||
// }
|
||||
// else
|
||||
// surveyTask.Planets.Remove(_targetPlanet);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// _entity.SetMessage("Survey complete. Returning Home.");
|
||||
// FinishTask();
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (!Moving)
|
||||
// {
|
||||
// var planetData = _context.ItemData.Get<BodyData>(_targetPlanet);
|
||||
// if ((!corporation.PlanetSurveyFloor.ContainsKey(_targetPlanet) ||
|
||||
// corporation.PlanetSurveyFloor[_targetPlanet] + .5f < _scanningTool.MinimumDensity) &&
|
||||
// length(_entity.Position - GetPosition(planetData, _asteroid)) < _scanningTool.Range)
|
||||
// {
|
||||
// _toolSwitch.Activated = true;
|
||||
// Aim.Objective = GetPosition(planetData, _asteroid);
|
||||
// Aim.Update(delta);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// _toolSwitch.Activated = false;
|
||||
// _taskStarted = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return base.Execute(delta);
|
||||
}
|
||||
|
||||
private void NextPlanet()
|
||||
{
|
||||
var planets = Task.Planets.Select(id => Zone.Planets[id]);
|
||||
var nearestPlanet = planets.MinBy(p => lengthsq(Entity.Position.xz - GetPosition(p)));
|
||||
_asteroid = nearestPlanet is AsteroidBeltData ? Zone.NearestAsteroid(nearestPlanet.ID, Entity.Position.xz) : -1;
|
||||
_targetPlanet = nearestPlanet.ID;
|
||||
}
|
||||
|
||||
private float2 GetPosition(BodyData planet, int asteroid = -1)
|
||||
{
|
||||
if (planet is AsteroidBeltData)
|
||||
{
|
||||
if(asteroid == -1) asteroid = Zone.NearestAsteroid(planet.ID, Entity.Position.xz);
|
||||
return Zone.AsteroidBelts[planet.ID].Positions[asteroid].xz;
|
||||
}
|
||||
return Zone.GetOrbitPosition(planet.Orbit);
|
||||
}
|
||||
|
||||
private float2 GetVelocity(BodyData planet, int asteroid = -1)
|
||||
{
|
||||
if (planet is AsteroidBeltData)
|
||||
{
|
||||
if(asteroid == -1) asteroid = Zone.NearestAsteroid(planet.ID, Entity.Position.xz);
|
||||
return Zone.AsteroidBelts[planet.ID].Velocities[asteroid];
|
||||
}
|
||||
return Zone.GetOrbitVelocity(planet.Orbit);
|
||||
}
|
||||
|
||||
public PersistentBehaviorData Store()
|
||||
{
|
||||
return new SurveyControllerPersistence
|
||||
{
|
||||
Task = Task
|
||||
};
|
||||
}
|
||||
|
||||
public void Restore(PersistentBehaviorData data)
|
||||
{
|
||||
var surveyControllerPersistence = data as SurveyControllerPersistence;
|
||||
Task = surveyControllerPersistence.Task;
|
||||
}
|
||||
}
|
||||
|
||||
public class SurveyControllerPersistence : PersistentBehaviorData
|
||||
{
|
||||
[JsonProperty("task"), Key(0)]
|
||||
public Survey Task;
|
||||
}
|
||||
// [MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship), Order(-100)]
|
||||
// public class SurveyControllerData : ControllerData
|
||||
// {
|
||||
// public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
|
||||
// {
|
||||
// return new SurveyController(context, this, entity, item);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public class SurveyController : ControllerBase<Survey>, IBehavior, IPersistentBehavior, IInitializableBehavior
|
||||
// {
|
||||
// private EquippedItem Item { get; }
|
||||
//
|
||||
// private SurveyControllerData _data;
|
||||
// private bool _taskStarted;
|
||||
// private ResourceScanner _scanningTool;
|
||||
// private Switch _toolSwitch;
|
||||
// private Guid _targetPlanet;
|
||||
// private int _asteroid = -1;
|
||||
//
|
||||
// public SurveyController(ItemManager itemManager, SurveyControllerData data, Entity entity, EquippedItem item) : base(itemManager, data, entity)
|
||||
// {
|
||||
// _data = data;
|
||||
// Item = item;
|
||||
// }
|
||||
//
|
||||
// public new void Initialize()
|
||||
// {
|
||||
// _scanningTool = Entity.GetBehavior<ResourceScanner>();
|
||||
// // _toolSwitch = Entity.GetSwitch<ResourceScanner>();
|
||||
// base.Initialize();
|
||||
// }
|
||||
//
|
||||
// public new bool Execute(float delta)
|
||||
// {
|
||||
// // var corporation = _context.ItemData.Get<Corporation>(_entity.Corporation);
|
||||
// // if (surveyTask != null)
|
||||
// // {
|
||||
// // if (!_taskStarted)
|
||||
// // {
|
||||
// // if (surveyTask.Planets.Any())
|
||||
// // {
|
||||
// // _entity.SetMessage("Moving to survey target.");
|
||||
// // NextPlanet();
|
||||
// // _scanningTool.ScanTarget = _targetPlanet;
|
||||
// // _scanningTool.Asteroid = _asteroid;
|
||||
// // if (!corporation.PlanetSurveyFloor.ContainsKey(_targetPlanet) ||
|
||||
// // corporation.PlanetSurveyFloor[_targetPlanet] + .5f < _scanningTool.MinimumDensity)
|
||||
// // {
|
||||
// // var planetData = _context.ItemData.Get<BodyData>(_targetPlanet);
|
||||
// // MoveTo(() =>
|
||||
// // {
|
||||
// // var target = GetPosition(planetData, _asteroid);
|
||||
// // var targetToUs = _entity.Position - target;
|
||||
// // return target + normalize(targetToUs) * _scanningTool.Range / 2;
|
||||
// // },
|
||||
// // () => GetVelocity(planetData, _asteroid),
|
||||
// // () => _entity.SetMessage("Arrived at target. Scanning for resources."));
|
||||
// // _taskStarted = true;
|
||||
// // }
|
||||
// // else
|
||||
// // surveyTask.Planets.Remove(_targetPlanet);
|
||||
// // }
|
||||
// // else
|
||||
// // {
|
||||
// // _entity.SetMessage("Survey complete. Returning Home.");
|
||||
// // FinishTask();
|
||||
// // }
|
||||
// // }
|
||||
// // else
|
||||
// // {
|
||||
// // if (!Moving)
|
||||
// // {
|
||||
// // var planetData = _context.ItemData.Get<BodyData>(_targetPlanet);
|
||||
// // if ((!corporation.PlanetSurveyFloor.ContainsKey(_targetPlanet) ||
|
||||
// // corporation.PlanetSurveyFloor[_targetPlanet] + .5f < _scanningTool.MinimumDensity) &&
|
||||
// // length(_entity.Position - GetPosition(planetData, _asteroid)) < _scanningTool.Range)
|
||||
// // {
|
||||
// // _toolSwitch.Activated = true;
|
||||
// // Aim.Objective = GetPosition(planetData, _asteroid);
|
||||
// // Aim.Update(delta);
|
||||
// // }
|
||||
// // else
|
||||
// // {
|
||||
// // _toolSwitch.Activated = false;
|
||||
// // _taskStarted = false;
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
// return base.Execute(delta);
|
||||
// }
|
||||
//
|
||||
// private void NextPlanet()
|
||||
// {
|
||||
// var planets = Task.Planets.Select(id => Zone.Planets[id]);
|
||||
// var nearestPlanet = planets.MinBy(p => lengthsq(Entity.Position.xz - GetPosition(p)));
|
||||
// _asteroid = nearestPlanet is AsteroidBeltData ? Zone.NearestAsteroid(nearestPlanet.ID, Entity.Position.xz) : -1;
|
||||
// _targetPlanet = nearestPlanet.ID;
|
||||
// }
|
||||
//
|
||||
// private float2 GetPosition(BodyData planet, int asteroid = -1)
|
||||
// {
|
||||
// if (planet is AsteroidBeltData)
|
||||
// {
|
||||
// if(asteroid == -1) asteroid = Zone.NearestAsteroid(planet.ID, Entity.Position.xz);
|
||||
// return Zone.AsteroidBelts[planet.ID].Positions[asteroid].xz;
|
||||
// }
|
||||
// return Zone.GetOrbitPosition(planet.Orbit);
|
||||
// }
|
||||
//
|
||||
// private float2 GetVelocity(BodyData planet, int asteroid = -1)
|
||||
// {
|
||||
// if (planet is AsteroidBeltData)
|
||||
// {
|
||||
// if(asteroid == -1) asteroid = Zone.NearestAsteroid(planet.ID, Entity.Position.xz);
|
||||
// return Zone.AsteroidBelts[planet.ID].Velocities[asteroid];
|
||||
// }
|
||||
// return Zone.GetOrbitVelocity(planet.Orbit);
|
||||
// }
|
||||
//
|
||||
// public PersistentBehaviorData Store()
|
||||
// {
|
||||
// return new SurveyControllerPersistence
|
||||
// {
|
||||
// Task = Task
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// public void Restore(PersistentBehaviorData data)
|
||||
// {
|
||||
// var surveyControllerPersistence = data as SurveyControllerPersistence;
|
||||
// Task = surveyControllerPersistence.Task;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public class SurveyControllerPersistence : PersistentBehaviorData
|
||||
// {
|
||||
// [JsonProperty("task"), Key(0)]
|
||||
// public Survey Task;
|
||||
// }
|
||||
|
|
@ -11,94 +11,94 @@ using Newtonsoft.Json;
|
|||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship), Order(-100)]
|
||||
public class TowingControllerData : ControllerData
|
||||
{
|
||||
public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
|
||||
{
|
||||
return new TowingController(context, this, entity, item);
|
||||
}
|
||||
}
|
||||
|
||||
public class TowingController : ControllerBase<StationTowing>, IBehavior, IPersistentBehavior
|
||||
{
|
||||
|
||||
private TowingControllerData _data;
|
||||
private EquippedItem Item { get; }
|
||||
private bool _taskStarted;
|
||||
|
||||
public TowingController(ItemManager itemManager, TowingControllerData data, Entity entity, EquippedItem item) : base(itemManager, data, entity)
|
||||
{
|
||||
_data = data;
|
||||
Item = item;
|
||||
}
|
||||
|
||||
public new bool Execute(float delta)
|
||||
{
|
||||
if (Task != null)
|
||||
{
|
||||
if (!_taskStarted)
|
||||
{
|
||||
MoveTo(Task.Station, true, OnPickup);
|
||||
_taskStarted = true;
|
||||
}
|
||||
}
|
||||
return base.Execute(delta);
|
||||
}
|
||||
|
||||
// void OnZoneArrival()
|
||||
// {
|
||||
// var towingTask = _context.ItemData.Get<StationTowing>(Task);
|
||||
//
|
||||
// _entity.SetMessage("Entering pickup phase.");
|
||||
//
|
||||
// MoveTo(_context.ItemData.Get<Entity>(towingTask.Station), true, OnPickup);
|
||||
// }
|
||||
|
||||
void OnPickup()
|
||||
{
|
||||
Task.Station.SetParent(Entity);
|
||||
|
||||
Entity.SetMessage("Entering delivery phase.");
|
||||
|
||||
MoveTo(() =>
|
||||
{
|
||||
var orbitParent = Zone.GetOrbitPosition(Task.OrbitParent);
|
||||
var parentToUs = Entity.Position.xz - orbitParent;
|
||||
return orbitParent + normalize(parentToUs) * Task.OrbitDistance;
|
||||
}, () => Zone.GetOrbitVelocity(Task.OrbitParent), OnDelivery);
|
||||
}
|
||||
|
||||
void OnDelivery()
|
||||
{
|
||||
Task.Station.RemoveParent();
|
||||
|
||||
Entity.SetMessage("Target delivered. Returning Home.");
|
||||
|
||||
var orbit = Zone.CreateOrbit(Task.OrbitParent, Entity.Position.xz);
|
||||
Task.Station.OrbitData = orbit.ID;
|
||||
|
||||
FinishTask();
|
||||
_taskStarted = false;
|
||||
}
|
||||
|
||||
public PersistentBehaviorData Store()
|
||||
{
|
||||
return new TowingControllerPersistence
|
||||
{
|
||||
Task = Task
|
||||
};
|
||||
}
|
||||
|
||||
public void Restore(PersistentBehaviorData data)
|
||||
{
|
||||
var towingControllerPersistence = data as TowingControllerPersistence;
|
||||
Task = towingControllerPersistence.Task;
|
||||
}
|
||||
}
|
||||
|
||||
public class TowingControllerPersistence : PersistentBehaviorData
|
||||
{
|
||||
[JsonProperty("task"), Key(0)]
|
||||
public StationTowing Task;
|
||||
}
|
||||
// [MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship), Order(-100)]
|
||||
// public class TowingControllerData : ControllerData
|
||||
// {
|
||||
// public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
|
||||
// {
|
||||
// return new TowingController(context, this, entity, item);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public class TowingController : ControllerBase<StationTowing>, IBehavior, IPersistentBehavior
|
||||
// {
|
||||
//
|
||||
// private TowingControllerData _data;
|
||||
// private EquippedItem Item { get; }
|
||||
// private bool _taskStarted;
|
||||
//
|
||||
// public TowingController(ItemManager itemManager, TowingControllerData data, Entity entity, EquippedItem item) : base(itemManager, data, entity)
|
||||
// {
|
||||
// _data = data;
|
||||
// Item = item;
|
||||
// }
|
||||
//
|
||||
// public new bool Execute(float delta)
|
||||
// {
|
||||
// if (Task != null)
|
||||
// {
|
||||
// if (!_taskStarted)
|
||||
// {
|
||||
// MoveTo(Task.Station, true, OnPickup);
|
||||
// _taskStarted = true;
|
||||
// }
|
||||
// }
|
||||
// return base.Execute(delta);
|
||||
// }
|
||||
//
|
||||
// // void OnZoneArrival()
|
||||
// // {
|
||||
// // var towingTask = _context.ItemData.Get<StationTowing>(Task);
|
||||
// //
|
||||
// // _entity.SetMessage("Entering pickup phase.");
|
||||
// //
|
||||
// // MoveTo(_context.ItemData.Get<Entity>(towingTask.Station), true, OnPickup);
|
||||
// // }
|
||||
//
|
||||
// void OnPickup()
|
||||
// {
|
||||
// Task.Station.SetParent(Entity);
|
||||
//
|
||||
// Entity.SetMessage("Entering delivery phase.");
|
||||
//
|
||||
// MoveTo(() =>
|
||||
// {
|
||||
// var orbitParent = Zone.GetOrbitPosition(Task.OrbitParent);
|
||||
// var parentToUs = Entity.Position.xz - orbitParent;
|
||||
// return orbitParent + normalize(parentToUs) * Task.OrbitDistance;
|
||||
// }, () => Zone.GetOrbitVelocity(Task.OrbitParent), OnDelivery);
|
||||
// }
|
||||
//
|
||||
// void OnDelivery()
|
||||
// {
|
||||
// Task.Station.RemoveParent();
|
||||
//
|
||||
// Entity.SetMessage("Target delivered. Returning Home.");
|
||||
//
|
||||
// var orbit = Zone.CreateOrbit(Task.OrbitParent, Entity.Position.xz);
|
||||
// Task.Station.OrbitData = orbit.ID;
|
||||
//
|
||||
// FinishTask();
|
||||
// _taskStarted = false;
|
||||
// }
|
||||
//
|
||||
// public PersistentBehaviorData Store()
|
||||
// {
|
||||
// return new TowingControllerPersistence
|
||||
// {
|
||||
// Task = Task
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// public void Restore(PersistentBehaviorData data)
|
||||
// {
|
||||
// var towingControllerPersistence = data as TowingControllerPersistence;
|
||||
// Task = towingControllerPersistence.Task;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public class TowingControllerPersistence : PersistentBehaviorData
|
||||
// {
|
||||
// [JsonProperty("task"), Key(0)]
|
||||
// public StationTowing Task;
|
||||
// }
|
||||
|
|
@ -105,7 +105,7 @@ public class TurretController : IBehavior
|
|||
}
|
||||
else
|
||||
{
|
||||
EquippedEntity.Target.Value = EquippedEntity.Zone.Entities.FirstOrDefault(e => e is Ship);
|
||||
EquippedEntity.Target.Value = EquippedEntity.VisibleHostiles.FirstOrDefault(e => e is Ship);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,67 +12,67 @@ using RethinkDb.Driver.Ast;
|
|||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship), Order(-100)]
|
||||
public class WanderControllerData : ControllerData
|
||||
{
|
||||
[InspectableField, JsonProperty("randomDockTime"), Key(6)]
|
||||
public float RandomDockTime = 5;
|
||||
|
||||
public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
|
||||
{
|
||||
return new WanderController(context, this, entity, item);
|
||||
}
|
||||
}
|
||||
|
||||
public class WanderController : ControllerBase<WanderTask>, IBehavior
|
||||
{
|
||||
public WanderTarget WanderTarget;
|
||||
|
||||
private WanderControllerData _data;
|
||||
private EquippedItem Item { get; }
|
||||
private Guid _target;
|
||||
private float _dockTime = -1;
|
||||
|
||||
public WanderController(ItemManager itemManager, WanderControllerData data, Entity entity, EquippedItem item) : base(itemManager, data, entity)
|
||||
{
|
||||
_data = data;
|
||||
Item = item;
|
||||
}
|
||||
|
||||
public new bool Execute(float delta)
|
||||
{
|
||||
if (!Moving && _dockTime < 0)
|
||||
{
|
||||
NextTarget();
|
||||
}
|
||||
|
||||
_dockTime -= delta;
|
||||
return base.Execute(delta);
|
||||
}
|
||||
|
||||
private void NextTarget()
|
||||
{
|
||||
if (WanderTarget == WanderTarget.Planets)
|
||||
{
|
||||
var planets = Zone.Planets.Values.ToArray();
|
||||
var randomPlanet = planets[ItemManager.Random.NextInt(planets.Length)];
|
||||
MoveTo(() => Zone.GetOrbitPosition(randomPlanet.Orbit), () => Zone.GetOrbitVelocity(randomPlanet.Orbit));
|
||||
}
|
||||
else if (WanderTarget == WanderTarget.Orbitals)
|
||||
{
|
||||
var entities = Zone.Entities.Where(e=>e is OrbitalEntity).ToArray();
|
||||
var randomEntity = entities[ItemManager.Random.NextInt(entities.Length)];
|
||||
MoveTo(randomEntity, true, () =>
|
||||
{
|
||||
Entity.SetParent(randomEntity);
|
||||
_dockTime = ItemManager.Random.NextFloat(_data.RandomDockTime);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum WanderTarget
|
||||
{
|
||||
Planets,
|
||||
Orbitals
|
||||
}
|
||||
// [MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship), Order(-100)]
|
||||
// public class WanderControllerData : ControllerData
|
||||
// {
|
||||
// [InspectableField, JsonProperty("randomDockTime"), Key(6)]
|
||||
// public float RandomDockTime = 5;
|
||||
//
|
||||
// public override IBehavior CreateInstance(ItemManager context, Entity entity, EquippedItem item)
|
||||
// {
|
||||
// return new WanderController(context, this, entity, item);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public class WanderController : ControllerBase<WanderTask>, IBehavior
|
||||
// {
|
||||
// public WanderTarget WanderTarget;
|
||||
//
|
||||
// private WanderControllerData _data;
|
||||
// private EquippedItem Item { get; }
|
||||
// private Guid _target;
|
||||
// private float _dockTime = -1;
|
||||
//
|
||||
// public WanderController(ItemManager itemManager, WanderControllerData data, Entity entity, EquippedItem item) : base(itemManager, data, entity)
|
||||
// {
|
||||
// _data = data;
|
||||
// Item = item;
|
||||
// }
|
||||
//
|
||||
// public new bool Execute(float delta)
|
||||
// {
|
||||
// if (!Moving && _dockTime < 0)
|
||||
// {
|
||||
// NextTarget();
|
||||
// }
|
||||
//
|
||||
// _dockTime -= delta;
|
||||
// return base.Execute(delta);
|
||||
// }
|
||||
//
|
||||
// private void NextTarget()
|
||||
// {
|
||||
// if (WanderTarget == WanderTarget.Planets)
|
||||
// {
|
||||
// var planets = Zone.Planets.Values.ToArray();
|
||||
// var randomPlanet = planets[ItemManager.Random.NextInt(planets.Length)];
|
||||
// MoveTo(() => Zone.GetOrbitPosition(randomPlanet.Orbit), () => Zone.GetOrbitVelocity(randomPlanet.Orbit));
|
||||
// }
|
||||
// else if (WanderTarget == WanderTarget.Orbitals)
|
||||
// {
|
||||
// var entities = Zone.Entities.Where(e=>e is OrbitalEntity).ToArray();
|
||||
// var randomEntity = entities[ItemManager.Random.NextInt(entities.Length)];
|
||||
// MoveTo(randomEntity, true, () =>
|
||||
// {
|
||||
// Entity.SetParent(randomEntity);
|
||||
// _dockTime = ItemManager.Random.NextFloat(_data.RandomDockTime);
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public enum WanderTarget
|
||||
// {
|
||||
// Planets,
|
||||
// Orbitals
|
||||
// }
|
||||
|
|
@ -73,6 +73,8 @@ public abstract class Weapon : IActivatedBehavior
|
|||
public EquippedItem Item { get; }
|
||||
public ItemManager Context { get; }
|
||||
|
||||
public abstract float DamagePerSecond { get; }
|
||||
public abstract float RangeDamagePerSecond(float range);
|
||||
public abstract int Ammo { get; }
|
||||
public WeaponData WeaponData => _data;
|
||||
public BehaviorData Data => _data;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ public abstract class Entity
|
|||
public readonly ReactiveCollection<EquippedItem> Equipment = new ReactiveCollection<EquippedItem>();
|
||||
public readonly ReactiveCollection<EquippedCargoBay> CargoBays = new ReactiveCollection<EquippedCargoBay>();
|
||||
public readonly ReactiveCollection<EquippedDockingBay> DockingBays = new ReactiveCollection<EquippedDockingBay>();
|
||||
public readonly ReactiveCollection<Entity> VisibleEntities = new ReactiveCollection<Entity>();
|
||||
public readonly ReactiveCollection<Entity> VisibleHostiles = new ReactiveCollection<Entity>();
|
||||
|
||||
public Entity Parent;
|
||||
public List<Entity> Children = new List<Entity>();
|
||||
|
|
@ -51,11 +53,11 @@ public abstract class Entity
|
|||
|
||||
public readonly Dictionary<string, float> Messages = new Dictionary<string, float>();
|
||||
public readonly Dictionary<object, float> VisibilitySources = new Dictionary<object, float>();
|
||||
public readonly Dictionary<Entity, float> EntityInfoGathered = new Dictionary<Entity, float>();
|
||||
public readonly ReactiveDictionary<Entity, float> EntityInfoGathered = new ReactiveDictionary<Entity, float>();
|
||||
public readonly Dictionary<HardpointData, (float3 position, float3 direction)> HardpointTransforms =
|
||||
new Dictionary<HardpointData, (float3 position, float3 direction)>();
|
||||
|
||||
public readonly (List<IActivatedBehavior> behaviors, List<EquippedItem> items)[] TriggerGroups;
|
||||
public readonly (List<Weapon> weapons, List<EquippedItem> items)[] TriggerGroups;
|
||||
|
||||
public List<IPopulationAssignment> PopulationAssignments = new List<IPopulationAssignment>();
|
||||
|
||||
|
|
@ -66,20 +68,20 @@ public abstract class Entity
|
|||
|
||||
private EquippedItem[] _orderedEquipment;
|
||||
private List<Weapon> _weapons = new List<Weapon>();
|
||||
private List<Weapon> _weaponsInRange = new List<Weapon>();
|
||||
protected bool _active;
|
||||
|
||||
public IEnumerable<Weapon> Weapons
|
||||
{
|
||||
get => _weapons;
|
||||
}
|
||||
public IEnumerable<Weapon> WeaponsInRange
|
||||
{
|
||||
get => _weaponsInRange;
|
||||
}
|
||||
|
||||
public float TargetRange { get; private set; }
|
||||
public float MaxTemp { get; private set; }
|
||||
public float MinTemp { get; private set; }
|
||||
public bool ShieldEnabled // TODO: MAKE SHIELDS
|
||||
{
|
||||
get => true;
|
||||
}
|
||||
public ItemManager ItemManager { get; }
|
||||
public int AssignedPopulation => PopulationAssignments.Sum(pa => pa.AssignedPopulation);
|
||||
public float Mass { get; private set; }
|
||||
|
|
@ -88,31 +90,48 @@ public abstract class Entity
|
|||
public Subject<(int2 pos, float damage)> ArmorDamage = new Subject<(int2, float)>();
|
||||
public Subject<(EquippedItem item, float damage)> ItemDamage = new Subject<(EquippedItem, float)>();
|
||||
public Subject<float> HullDamage = new Subject<float>();
|
||||
public Subject<Entity> Docked = new Subject<Entity>();
|
||||
|
||||
public UniRx.IObservable<EquippedItem> ItemDestroyed;
|
||||
public UniRx.IObservable<int2> HullArmorDepleted;
|
||||
public UniRx.IObservable<HardpointData> HardpointArmorDepleted;
|
||||
public UniRx.IObservable<Weapon> WeaponDestroyed;
|
||||
|
||||
public bool Active
|
||||
private List<IDisposable> _subscriptions = new List<IDisposable>();
|
||||
|
||||
public virtual void Activate()
|
||||
{
|
||||
get => _active;
|
||||
set
|
||||
_active = true;
|
||||
foreach (var item in Equipment)
|
||||
foreach (var behavior in item.Behaviors)
|
||||
{
|
||||
_active = value;
|
||||
if (_active)
|
||||
{
|
||||
foreach (var item in Equipment)
|
||||
foreach (var behavior in item.Behaviors)
|
||||
{
|
||||
if(behavior is IInitializableBehavior initializableBehavior)
|
||||
initializableBehavior.Initialize();
|
||||
}
|
||||
OnActivate();
|
||||
}
|
||||
if(behavior is IInitializableBehavior initializableBehavior)
|
||||
initializableBehavior.Initialize();
|
||||
}
|
||||
//foreach(var entity in Zone.Entities) EntityInfoGathered.Add(entity, 0);
|
||||
_subscriptions.Add(Zone.Entities.ObserveRemove().Subscribe(remove =>
|
||||
{
|
||||
if (Target.Value == remove.Value) Target.Value = null;
|
||||
EntityInfoGathered.Remove(remove.Value);
|
||||
VisibleEntities.Remove(remove.Value);
|
||||
VisibleHostiles.Remove(remove.Value);
|
||||
}));
|
||||
_subscriptions.Add(VisibleEntities.ObserveRemove().Subscribe(remove =>
|
||||
{
|
||||
if (Target.Value == remove.Value) Target.Value = null;
|
||||
}));
|
||||
GenerateTriggerGroups();
|
||||
}
|
||||
|
||||
protected virtual void OnActivate(){}
|
||||
public virtual void Deactivate()
|
||||
{
|
||||
foreach(var s in _subscriptions) s.Dispose();
|
||||
_subscriptions.Clear();
|
||||
_active = false;
|
||||
EntityInfoGathered.Clear();
|
||||
VisibleEntities.Clear();
|
||||
VisibleHostiles.Clear();
|
||||
}
|
||||
|
||||
public Entity(ItemManager itemManager, Zone zone, EquippableItem hull)
|
||||
{
|
||||
|
|
@ -121,12 +140,42 @@ public abstract class Entity
|
|||
Hull = hull;
|
||||
Name = hull.Name;
|
||||
MapEntity();
|
||||
TriggerGroups = new (List<IActivatedBehavior> triggers, List<EquippedItem> items)[itemManager.GameplaySettings.TriggerGroupCount];
|
||||
TriggerGroups = new (List<Weapon> triggers, List<EquippedItem> items)[itemManager.GameplaySettings.TriggerGroupCount];
|
||||
for(int i=0; i<itemManager.GameplaySettings.TriggerGroupCount; i++)
|
||||
TriggerGroups[i] = (new List<IActivatedBehavior>(), new List<EquippedItem>());
|
||||
TriggerGroups[i] = (new List<Weapon>(), new List<EquippedItem>());
|
||||
|
||||
ItemDestroyed = ItemDamage.Where(x => x.item.EquippableItem.Durability < .01f).Select(x=>x.item);
|
||||
WeaponDestroyed = ItemDestroyed.Select(x => x.Behaviors.FirstOrDefault(b => b is Weapon) as Weapon).Where(x => x != null);
|
||||
HullArmorDepleted = ArmorDamage.Where(x => Armor[x.pos.x, x.pos.y] < .01f).Select(x => x.pos);
|
||||
|
||||
EntityInfoGathered.ObserveReplace().Subscribe(replace =>
|
||||
{
|
||||
if (replace.OldValue < ItemManager.GameplaySettings.TargetDetectionInfoThreshold &&
|
||||
replace.NewValue > ItemManager.GameplaySettings.TargetDetectionInfoThreshold)
|
||||
{
|
||||
VisibleEntities.Add(replace.Key);
|
||||
if(IsHostileTo(replace.Key))
|
||||
VisibleHostiles.Add(replace.Key);
|
||||
}
|
||||
if (replace.OldValue > ItemManager.GameplaySettings.TargetDetectionInfoThreshold &&
|
||||
replace.NewValue < ItemManager.GameplaySettings.TargetDetectionInfoThreshold)
|
||||
{
|
||||
VisibleEntities.Remove(replace.Key);
|
||||
if(IsHostileTo(replace.Key))
|
||||
VisibleHostiles.Add(replace.Key);
|
||||
}
|
||||
});
|
||||
EntityInfoGathered.ObserveRemove().Subscribe(remove => VisibleEntities.Remove(remove.Key));
|
||||
}
|
||||
|
||||
public bool IsHostileTo(Entity other)
|
||||
{
|
||||
if (Faction == null)
|
||||
{
|
||||
return other.Faction != null;
|
||||
}
|
||||
|
||||
return Faction.PlayerHostile && other.Faction == null;
|
||||
}
|
||||
|
||||
private void MapEntity()
|
||||
|
|
@ -165,6 +214,17 @@ public abstract class Entity
|
|||
GearOccupancy = new EquippedItem[hullData.Shape.Width, hullData.Shape.Height];
|
||||
}
|
||||
|
||||
public void GenerateTriggerGroups()
|
||||
{
|
||||
foreach (var group in Weapons
|
||||
.GroupBy(w => w.Item.EquippableItem.Data)
|
||||
.Select((weapons, index) => (weapons, index)))
|
||||
{
|
||||
TriggerGroups[group.index].weapons = group.weapons.ToList();
|
||||
TriggerGroups[group.index].items = group.weapons.Select(w=>w.Item).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddHeat(int2 position, float heat, bool ignoreThermalMass = false)
|
||||
{
|
||||
if (ignoreThermalMass)
|
||||
|
|
@ -439,6 +499,8 @@ public abstract class Entity
|
|||
bay.DockedShip = ship;
|
||||
ship.SetParent(this);
|
||||
Zone.Entities.Remove(ship);
|
||||
Deactivate();
|
||||
ship.Docked.OnNext(this);
|
||||
}
|
||||
|
||||
return bay;
|
||||
|
|
@ -459,6 +521,7 @@ public abstract class Entity
|
|||
bay.DockedShip = null;
|
||||
ship.RemoveParent();
|
||||
Zone.Entities.Add(ship);
|
||||
ship.Activate();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -556,15 +619,8 @@ public abstract class Entity
|
|||
public virtual void Update(float delta)
|
||||
{
|
||||
var hullData = ItemManager.GetData(Hull) as HullData;
|
||||
|
||||
_weaponsInRange.Clear();
|
||||
if (Target.Value != null)
|
||||
{
|
||||
var dist = length(Position - Target.Value.Position);
|
||||
foreach (var w in _weapons)
|
||||
if (w.MinRange < dist && dist < w.Range)
|
||||
_weaponsInRange.Add(w);
|
||||
}
|
||||
|
||||
TargetRange = Target.Value == null ? -1 : length(Position - Target.Value.Position);
|
||||
|
||||
foreach (var v in VisibilitySources.Keys.ToArray())
|
||||
{
|
||||
|
|
@ -572,6 +628,37 @@ public abstract class Entity
|
|||
|
||||
if (VisibilitySources[v] < 0.01f) VisibilitySources.Remove(v);
|
||||
}
|
||||
|
||||
UpdateTemperature(delta);
|
||||
|
||||
if (_active)
|
||||
{
|
||||
foreach (var equippedItem in _orderedEquipment)
|
||||
{
|
||||
equippedItem.Update(delta);
|
||||
}
|
||||
|
||||
foreach (var message in Messages.Keys.ToArray())
|
||||
{
|
||||
Messages[message] = Messages[message] - delta;
|
||||
if (Messages[message] < 0)
|
||||
Messages.Remove(message);
|
||||
}
|
||||
}
|
||||
foreach(var child in Children)
|
||||
child.Update(delta);
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
Position = Parent.Position;
|
||||
Velocity = Parent.Velocity;
|
||||
}
|
||||
else Position.y = Zone.GetHeight(Position.xz) + hullData.GridOffset;
|
||||
}
|
||||
|
||||
private void UpdateTemperature(float delta)
|
||||
{
|
||||
var hullData = ItemManager.GetData(Hull) as HullData;
|
||||
|
||||
MaxTemp = Single.MinValue;
|
||||
MinTemp = Single.MaxValue;
|
||||
|
|
@ -657,65 +744,12 @@ public abstract class Entity
|
|||
var swap = Temperature;
|
||||
Temperature = NewTemperature;
|
||||
NewTemperature = swap;
|
||||
|
||||
if (Active)
|
||||
{
|
||||
foreach (var equippedItem in _orderedEquipment)
|
||||
{
|
||||
equippedItem.Update(delta);
|
||||
}
|
||||
|
||||
foreach (var message in Messages.Keys.ToArray())
|
||||
{
|
||||
Messages[message] = Messages[message] - delta;
|
||||
if (Messages[message] < 0)
|
||||
Messages.Remove(message);
|
||||
}
|
||||
}
|
||||
foreach(var child in Children)
|
||||
child.Update(delta);
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
Position = Parent.Position;
|
||||
Velocity = Parent.Velocity;
|
||||
}
|
||||
else Position.y = Zone.GetHeight(Position.xz) + hullData.GridOffset;
|
||||
}
|
||||
|
||||
public void SetMessage(string message)
|
||||
{
|
||||
Messages[message] = ItemManager.GameplaySettings.MessageDuration;
|
||||
}
|
||||
|
||||
// public void OnBeforeSerialize()
|
||||
// {
|
||||
// // Filter item behavior collections by those with any persistent behaviors
|
||||
// // For each item create an object containing the item ID and a list of persistent behaviors
|
||||
// // Then turn that into a dictionary mapping from item ID to an array of every behaviors persistent data
|
||||
// PersistedBehaviors = EquippedItems
|
||||
// .Where(item => item.Behaviors.Any(b=>b is IPersistentBehavior))
|
||||
// .Select(item => new {equippable=item, behaviors = item.Behaviors
|
||||
// .Where(b=>b is IPersistentBehavior)
|
||||
// .Cast<IPersistentBehavior>()})
|
||||
// .ToDictionary(x=> x.equippable.Position, x=>x.behaviors.Select(b => b.Store()).ToArray());
|
||||
// }
|
||||
//
|
||||
// public void OnAfterDeserialize()
|
||||
// {
|
||||
// foreach(var item in EquippedItems)
|
||||
// Hydrate(item);
|
||||
//
|
||||
// // Iterate only over the behaviors of items which contain persistent data
|
||||
// // Filter the behaviors for each item to get the persistent ones, then cast them and combine with the persisted data array for that item
|
||||
// foreach (var persistentBehaviorData in EquippedItems
|
||||
// .Where(item => PersistedBehaviors.ContainsKey(item.Position))
|
||||
// .SelectMany(item => item.Behaviors
|
||||
// .Where(b=> b is IPersistentBehavior)
|
||||
// .Cast<IPersistentBehavior>()
|
||||
// .Zip(PersistedBehaviors[item.Position], (behavior, data) => new{behavior, data})))
|
||||
// persistentBehaviorData.behavior.Restore(persistentBehaviorData.data);
|
||||
// }
|
||||
}
|
||||
|
||||
public class EquippedItem
|
||||
|
|
@ -727,6 +761,9 @@ public class EquippedItem
|
|||
public IBehavior[] Behaviors;
|
||||
|
||||
public Dictionary<int, BehaviorGroup> BehaviorGroups;
|
||||
|
||||
public event Action OnDisable;
|
||||
public event Action OnEnable;
|
||||
|
||||
public float Conductivity { get; }
|
||||
|
||||
|
|
@ -734,7 +771,10 @@ public class EquippedItem
|
|||
|
||||
public int SortPosition;
|
||||
|
||||
public bool Online => EquippableItem.Durability > .01f && Temperature > _data.MinimumTemperature && Temperature < _data.MaximumTemperature;
|
||||
public bool Online
|
||||
{
|
||||
get => _online;
|
||||
}
|
||||
|
||||
public float Temperature
|
||||
{
|
||||
|
|
@ -749,6 +789,7 @@ public class EquippedItem
|
|||
protected readonly ItemManager _itemManager;
|
||||
private readonly EquippableItemData _data;
|
||||
private Entity _entity;
|
||||
private bool _online;
|
||||
|
||||
public EquippedItem(ItemManager itemManager, EquippableItem item, int2 position, Entity entity)
|
||||
{
|
||||
|
|
@ -792,16 +833,22 @@ public class EquippedItem
|
|||
|
||||
public void Update(float delta)
|
||||
{
|
||||
|
||||
if (Temperature < _data.MinimumTemperature || Temperature > _data.MaximumTemperature)
|
||||
{
|
||||
_entity.ItemDamage.OnNext((this, delta));
|
||||
EquippableItem.Durability -= delta;
|
||||
}
|
||||
|
||||
foreach (var behavior in Behaviors)//.Where(b => b is IAlwaysUpdatedBehavior).Cast<IAlwaysUpdatedBehavior>())
|
||||
foreach (var behavior in Behaviors)
|
||||
if(behavior is IAlwaysUpdatedBehavior alwaysUpdatedBehavior) alwaysUpdatedBehavior.Update(delta);
|
||||
|
||||
if (Online)
|
||||
var previouslyOnline = _online;
|
||||
_online = EquippableItem.Durability > .01f && Temperature > _data.MinimumTemperature && Temperature < _data.MaximumTemperature;
|
||||
|
||||
if (!previouslyOnline && _online) OnEnable?.Invoke();
|
||||
if (previouslyOnline && !_online) OnDisable?.Invoke();
|
||||
|
||||
if (_online)
|
||||
{
|
||||
foreach (var group in BehaviorGroups.Values)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -114,12 +114,14 @@ public class EntityPack
|
|||
}
|
||||
|
||||
for (var bayIndex = 0; bayIndex < pack.CargoContents.Length; bayIndex++)
|
||||
foreach (var (position, item) in pack.CargoContents[bayIndex])
|
||||
entity.CargoBays[bayIndex].TryStore(instantiate ? itemManager.Instantiate(item) : item, position);
|
||||
if(entity.CargoBays.Count >= bayIndex + 1)
|
||||
foreach (var (position, item) in pack.CargoContents[bayIndex])
|
||||
entity.CargoBays[bayIndex].TryStore(instantiate ? itemManager.Instantiate(item) : item, position);
|
||||
|
||||
for (var bayIndex = 0; bayIndex < pack.DockingBayContents.Length; bayIndex++)
|
||||
foreach (var (position, item) in pack.DockingBayContents[bayIndex])
|
||||
entity.DockingBays[bayIndex].TryStore(instantiate ? itemManager.Instantiate(item) : item, position);
|
||||
if(entity.DockingBays.Count >= bayIndex + 1)
|
||||
foreach (var (position, item) in pack.DockingBayContents[bayIndex])
|
||||
entity.DockingBays[bayIndex].TryStore(instantiate ? itemManager.Instantiate(item) : item, position);
|
||||
|
||||
// Iterate only over the behaviors of items which contain persistent data
|
||||
// Filter the behaviors for each item to get the persistent ones, then cast them and combine with the persisted data array for that item
|
||||
|
|
|
|||
|
|
@ -289,14 +289,10 @@ public static class Extensions
|
|||
return t * (t * (a * t + b) + c) + d;
|
||||
}
|
||||
|
||||
public static float AngleDiff(this float2 a, float2 b)
|
||||
public static float Angle(this float2 from, float2 to)
|
||||
{
|
||||
var directionAngle = atan2(b.y, b.x);
|
||||
var currentAngle = atan2(a.y, a.x);
|
||||
var d1 = directionAngle - currentAngle;
|
||||
var d2 = directionAngle - 2 * PI - currentAngle;
|
||||
var d3 = directionAngle + 2 * PI - currentAngle;
|
||||
return abs(d1) < abs(d2) ? abs(d1) < abs(d3) ? d1 : d3 : abs(d2) < abs(d3) ? d2 : d3;
|
||||
var num = sqrt(lengthsq(from) * lengthsq(to));
|
||||
return num < 1.00000000362749E-15 ? 0.0f : acos(clamp(dot(from, to) / num, -1f, 1f)) * 57.29578f;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/3188835
|
||||
|
|
|
|||
|
|
@ -1,10 +1,4 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
public static class Noise1D
|
||||
|
|
|
|||
|
|
@ -116,4 +116,8 @@ public class GameplaySettings
|
|||
public float TargetArmorInfoThreshold;
|
||||
public float TargetGearInfoThreshold;
|
||||
public float ConvergenceMinimumDistance;
|
||||
public float AgentRangeExponent = .25f;
|
||||
public float AgentForwardLerp = .5f;
|
||||
public float AgentMaxForwardDistance = 50;
|
||||
public float AgentFiringMinDot = .99f;
|
||||
}
|
||||
|
|
@ -40,11 +40,20 @@ public class Ship : Entity
|
|||
public float RightStrafeThrust { get; private set; }
|
||||
public float ClockwiseTorque { get; private set; }
|
||||
public float CounterClockwiseTorque { get; private set; }
|
||||
|
||||
public float TurnTime(float2 direction)
|
||||
{
|
||||
var angleDiff = Direction.Angle(normalize(direction));
|
||||
var clockwise = dot(direction, Direction.Rotate(ItemRotation.Clockwise)) > 0;
|
||||
return angleDiff / ((clockwise ? ClockwiseTorque : CounterClockwiseTorque) / Mass);
|
||||
}
|
||||
|
||||
public quaternion Rotation { get; private set; }
|
||||
|
||||
protected override void OnActivate()
|
||||
public override void Activate()
|
||||
{
|
||||
base.Activate();
|
||||
|
||||
_allThrusters = GetBehaviors<Thruster>().ToArray();
|
||||
|
||||
_forwardThrusters = new HashSet<Thruster>(_allThrusters
|
||||
|
|
|
|||
Loading…
Reference in a new issue