Skip to content

Commit

Permalink
lavaland-changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Fragoler committed Aug 10, 2024
1 parent c803db0 commit 74605f2
Show file tree
Hide file tree
Showing 11 changed files with 316 additions and 1 deletion.
1 change: 1 addition & 0 deletions Content.Client/Entry/EntryPoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ public override void Init()
_prototypeManager.RegisterIgnore("nukeopsRole");
_prototypeManager.RegisterIgnore("stationGoal"); // Corvax-StationGoal
_prototypeManager.RegisterIgnore("ghostRoleRaffleDecider");
_prototypeManager.RegisterIgnore("spawnGroupProto"); // Exodus-Lavaland

_componentFactory.GenerateNetIds();
_adminManager.Initialize();
Expand Down
4 changes: 4 additions & 0 deletions Content.Server/Explosion/EntitySystems/TriggerSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ private void OnSoundTrigger(EntityUid uid, SoundOnTriggerComponent component, Tr
{
var xform = Transform(uid);
_audio.PlayPvs(component.Sound, xform.Coordinates); // play the sound at its last known coordinates

// Exodus-Lavaland-start
RemCompDeferred<SoundOnTriggerComponent>(uid);
// Exodus-Lavaland-end
}
else // if the component doesn't get removed when triggered
{
Expand Down
56 changes: 56 additions & 0 deletions Content.Server/NPC/Components/NPCAbilityCombatComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Exodus-Lavaland
namespace Content.Server.NPC.Components;

/// <summary>
/// Added to NPCs whenever they're in ability combat so they can be handled by the dedicated system.
/// </summary>
[RegisterComponent]
public sealed partial class NPCAbilityCombatComponent : Component
{
[ViewVariables]
public EntityUid Target;

[ViewVariables]
public AbilityCombatStatus Status = AbilityCombatStatus.Normal;

[ViewVariables]
public TimeSpan NextAction = new();

[ViewVariables]
public int ActionsPerUpd = 1;

[ViewVariables]
public int UsedActionsLastUpd = 0;

[ViewVariables]
public float ActionsTimeReload = 1.0f;

}

public enum AbilityCombatStatus : byte
{
/// <summary>
/// The target isn't in LOS anymore.
/// </summary>
NotInSight,

/// <summary>
/// Due to some generic reason we are unable to attack the target.
/// </summary>
Unspecified,

/// <summary>
/// Set if we can't reach the target for whatever reason.
/// </summary>
TargetUnreachable,

/// <summary>
/// If the target is outside of our melee range.
/// </summary>
TargetOutOfRange,

/// <summary>
/// No dramas.
/// </summary>
Normal,
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ public sealed partial class JukeOperator : HTNOperator, IHtnConditionalShutdown
[DataField("jukeType")]
public JukeType JukeType = JukeType.AdjacentTile;

// Exodus-Lavaland-AdvancedAI-Start
[DataField("jukeDuration")]
public float JukeDuration = 0.5f;
// Exodus-Lavaland-AdvancedAI-End

[DataField("shutdownState")]
public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.PlanFinished;

Expand All @@ -17,6 +22,7 @@ public override void Startup(NPCBlackboard blackboard)
base.Startup(blackboard);
var juke = _entManager.EnsureComponent<NPCJukeComponent>(blackboard.GetValue<EntityUid>(NPCBlackboard.Owner));
juke.JukeType = JukeType;
juke.JukeDuration = JukeDuration; // Exodus-Lavaland-AdvancedAI
}

public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
Expand Down
1 change: 1 addition & 0 deletions Content.Server/NPC/Systems/NPCCombatSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@ public override void Update(float frameTime)
base.Update(frameTime);
UpdateMelee(frameTime);
UpdateRanged(frameTime);
UpdateAbility(frameTime); // Exodus-Lavaland
}
}
238 changes: 238 additions & 0 deletions Content.Server/NPC/Systems/NPCCombatSystrem.Ability.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
using System.Numerics;
using Content.Server.NPC.Components;
using Content.Shared.NPC;
using Robust.Shared.Map;
using Robust.Shared.Physics.Components;
using Robust.Shared.Random;
using Content.Shared.ActionBlocker;
using Content.Shared.Actions.Events;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;

using Content.Shared.Interaction;
using Content.Shared.Actions;
using Content.Server.Actions;
using Content.Shared.Directions;

namespace Content.Server.NPC.Systems;

public sealed partial class NPCCombatSystem
{
[Dependency] private readonly ActionsSystem _actions = default!;
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly RotateToFaceSystem _rotateToFaceSystem = default!;

private const float TargetAbilityLostRange = 28f;

private void InitializeAbility()
{
SubscribeLocalEvent<NPCAbilityCombatComponent, ComponentShutdown>(OnAbilityShutdown);
}

private void OnAbilityShutdown(EntityUid uid, NPCAbilityCombatComponent component, ComponentShutdown args)
{
_steering.Unregister(uid);
}

private void UpdateAbility(float frameTime)
{
var xformQuery = GetEntityQuery<TransformComponent>();
var physicsQuery = GetEntityQuery<PhysicsComponent>();
var curTime = _timing.CurTime;
var query = EntityQueryEnumerator<NPCAbilityCombatComponent, ActiveNPCComponent>();

while (query.MoveNext(out var uid, out var comp, out _))
{
CastAction(uid, comp, curTime, physicsQuery, xformQuery);
}
}

private void CastAction(EntityUid uid, NPCAbilityCombatComponent combatComp, TimeSpan curTime, EntityQuery<PhysicsComponent> physicsQuery, EntityQuery<TransformComponent> xformQuery)
{
combatComp.Status = AbilityCombatStatus.Normal;

if (!xformQuery.TryGetComponent(uid, out var xform) ||
!xformQuery.TryGetComponent(combatComp.Target, out var targetXform))
{
combatComp.Status = AbilityCombatStatus.TargetUnreachable;
return;
}

if (!xform.Coordinates.TryDistance(EntityManager, targetXform.Coordinates, out var distance))
{
combatComp.Status = AbilityCombatStatus.TargetUnreachable;
return;
}

if (distance > TargetMeleeLostRange)
{
combatComp.Status = AbilityCombatStatus.TargetUnreachable;
return;
}

if (TryComp<NPCSteeringComponent>(uid, out var steering) &&
steering.Status == SteeringStatus.NoPath)
{
combatComp.Status = AbilityCombatStatus.TargetUnreachable;
return;
}

_steering.Register(uid, new EntityCoordinates(combatComp.Target, Vector2.Zero), steering);

if (combatComp.NextAction > curTime)
return;

// Get Actions
if (!TryComp(uid, out ActionsComponent? actionComp))
return;

List<EntityUid> actions = [];
actions.AddRange(actionComp.Actions);

while (actions.Count > 0)
{
if (combatComp.UsedActionsLastUpd >= combatComp.ActionsPerUpd)
break;

var act = _random.PickAndTake(actions);

var attemptEv = new ActionAttemptEvent(uid);
RaiseLocalEvent(act, ref attemptEv);
if (attemptEv.Cancelled)
return;

if (TryUseAction(uid, act, distance, combatComp, curTime))
combatComp.UsedActionsLastUpd++;
}

if (combatComp.UsedActionsLastUpd >= combatComp.ActionsPerUpd)
{
combatComp.UsedActionsLastUpd = 0;
combatComp.NextAction = curTime + TimeSpan.FromSeconds(combatComp.ActionsTimeReload);
}
}

private bool TryUseAction(EntityUid uid,
EntityUid actionUid,
float distance,
NPCAbilityCombatComponent combatComp,
TimeSpan curTime)
{
if (!TryComp(uid, out ActionsComponent? actionComp))
return false;

if (!TryComp(actionUid, out MetaDataComponent? actionMeta))
return false;

if (!_actions.TryGetActionData(actionUid, out var action))
return false;

if (!action.Enabled)
return false;

// check for action use prevention
var attemptEv = new ActionAttemptEvent(uid);
RaiseLocalEvent(actionUid, ref attemptEv);
if (attemptEv.Cancelled)
return false;

if (action.Cooldown.HasValue && action.Cooldown.Value.End > curTime)
return false;

if (action is { Charges: < 1, RenewCharges: true })
_actions.ResetCharges(actionUid);

BaseActionEvent? performEvent = null;

if (action.CheckConsciousness && !_actionBlockerSystem.CanConsciouslyPerformAction(uid))
return false;

if (!combatComp.Target.IsValid())
{
Log.Error($"Attempted to perform an entity-targeted action without a target! Action: {actionMeta.EntityName}");
return false;
}

if (action.MinAIUseRange >= distance ||
action.MaxAIUseRange <= distance)
{
Log.Error("Out");
return false;
}

// Validate request by checking action blockers and the like:
switch (action)
{
case EntityTargetActionComponent entityAction:
var targetWorldPos = _transform.GetWorldPosition(combatComp.Target);

if (entityAction.Range <= distance)
return false;

_rotateToFaceSystem.TryFaceCoordinates(uid, targetWorldPos);

if (!_actions.ValidateEntityTarget(uid, combatComp.Target, (actionUid, entityAction)))
return false;

_adminLogger.Add(LogType.Action,
$"{ToPrettyString(uid):user} is performing the {actionMeta.EntityName:action} action (provided by {ToPrettyString(action.Container ?? uid):provider}) targeted at {ToPrettyString(combatComp.Target):target}.");

if (entityAction.Event != null)
{
entityAction.Event.Target = combatComp.Target;
Dirty(actionUid, entityAction);
performEvent = entityAction.Event;
}
break;
case WorldTargetActionComponent worldAction:
var entityCoordinatesTarget = Transform(combatComp.Target).Coordinates;

if (worldAction.Range <= distance)
{
var mapTargetPos = entityCoordinatesTarget.ToMapPos(EntityManager, _transform);
var mapUserPos = Transform(uid).Coordinates.ToMapPos(EntityManager, _transform);

var direction = mapTargetPos - mapUserPos;
var coefficient = worldAction.Range / distance;
var delta = new Vector2(direction.X * coefficient, direction.Y * coefficient);
entityCoordinatesTarget = new EntityCoordinates(entityCoordinatesTarget.EntityId, mapUserPos + delta);
}

_rotateToFaceSystem.TryFaceCoordinates(uid, entityCoordinatesTarget.ToMapPos(EntityManager, _transform));

if (!_actions.ValidateWorldTarget(uid, entityCoordinatesTarget, (actionUid, worldAction)))
return false;

_adminLogger.Add(LogType.Action,
$"{ToPrettyString(uid):user} is performing the {actionMeta.EntityName:action} action (provided by {ToPrettyString(action.Container ?? uid):provider}) targeted at {entityCoordinatesTarget:target}.");

if (worldAction.Event != null)
{
worldAction.Event.Target = entityCoordinatesTarget;
Dirty(actionUid, worldAction);
performEvent = worldAction.Event;
}

break;
case InstantActionComponent instantAction:
if (action.CheckCanInteract && !_actionBlockerSystem.CanInteract(uid, null))
return false;

_adminLogger.Add(LogType.Action,
$"{ToPrettyString(uid):user} is performing the {actionMeta.EntityName:action} action provided by {ToPrettyString(action.Container ?? uid):provider}.");

performEvent = instantAction.Event;
break;
}

if (performEvent != null)
performEvent.Performer = uid;

// All checks passed. Perform the action!
_actions.PerformAction(uid, actionComp, actionUid, action, performEvent, curTime);

return true;
}

}
5 changes: 5 additions & 0 deletions Content.Shared/Actions/BaseActionComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@ public EntityUid? EntityIcon
/// If not null, this sound will be played when performing this action.
/// </summary>
[DataField("sound")] public SoundSpecifier? Sound;

// Exodus-Lavaland-Start
[DataField("maxUseRange")] public float MaxAIUseRange = float.PositiveInfinity;
[DataField("minUseRange")] public float MinAIUseRange = 0;
// Exodus-Lavaland-End
}

[Serializable, NetSerializable]
Expand Down
2 changes: 1 addition & 1 deletion Content.Shared/Magic/Events/ProjectileSpellEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ public sealed partial class ProjectileSpellEvent : WorldTargetActionEvent, ISpea
public EntProtoId Prototype;

[DataField]
public string? Speech { get; private set; }
public string? Speech { get; set; } // Exodus-Lavaland
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- files: ["spawn.ogg", "bum.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Taken from Zvukipro.com"
source: "https://zvukipro.com/electronic/368-zvuki-lazera.html"
Binary file not shown.
Binary file not shown.

0 comments on commit 74605f2

Please sign in to comment.