You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
4.6 KiB
C#
118 lines
4.6 KiB
C#
3 weeks ago
|
using System;
|
||
|
using Unity.BossRoom.Gameplay.GameplayObjects;
|
||
|
using Unity.BossRoom.Gameplay.GameplayObjects.Character;
|
||
|
using UnityEngine;
|
||
|
|
||
|
namespace Unity.BossRoom.Gameplay.Actions
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Causes the attacker to teleport near a target spot, then perform a melee attack. The client
|
||
|
/// visualization moves the character locally beforehand, making the character appear to dash to the
|
||
|
/// destination spot.
|
||
|
///
|
||
|
/// After the ExecTime has elapsed, the character is immune to damage until the action ends.
|
||
|
///
|
||
|
/// Since the "Range" field means "range when we can teleport to our target", we need another
|
||
|
/// field to mean "range of our melee attack after dashing". We'll use the "Radius" field of the
|
||
|
/// ActionDescription for that.
|
||
|
/// </summary>
|
||
|
/// <remarks>
|
||
|
/// See MeleeAction for relevant discussion about targeting; we use the same concept here: preferring
|
||
|
/// the chosen target, but using whatever is actually within striking distance at time of attack.
|
||
|
/// </remarks>
|
||
|
[CreateAssetMenu(menuName = "BossRoom/Actions/Dash Attack Action")]
|
||
|
public class DashAttackAction : Action
|
||
|
{
|
||
|
private Vector3 m_TargetSpot;
|
||
|
|
||
|
private bool m_Dashed;
|
||
|
|
||
|
public override bool OnStart(ServerCharacter serverCharacter)
|
||
|
{
|
||
|
// remember the exact spot we'll stop.
|
||
|
m_TargetSpot = ActionUtils.GetDashDestination(serverCharacter.physicsWrapper.Transform, Data.Position, true, Config.Range, Config.Range);
|
||
|
|
||
|
// snap to face our destination. This ensures the client visualization faces the right way while "pretending" to dash
|
||
|
serverCharacter.physicsWrapper.Transform.LookAt(m_TargetSpot);
|
||
|
|
||
|
serverCharacter.serverAnimationHandler.NetworkAnimator.SetTrigger(Config.Anim);
|
||
|
|
||
|
// tell clients to visualize this action
|
||
|
serverCharacter.clientCharacter.ClientPlayActionRpc(Data);
|
||
|
|
||
|
return ActionConclusion.Continue;
|
||
|
}
|
||
|
|
||
|
public override void Reset()
|
||
|
{
|
||
|
base.Reset();
|
||
|
m_TargetSpot = default;
|
||
|
m_Dashed = false;
|
||
|
}
|
||
|
|
||
|
public override bool OnUpdate(ServerCharacter clientCharacter)
|
||
|
{
|
||
|
return ActionConclusion.Continue;
|
||
|
}
|
||
|
|
||
|
public override void End(ServerCharacter serverCharacter)
|
||
|
{
|
||
|
// Anim2 contains the name of the end-loop-sequence trigger
|
||
|
if (!string.IsNullOrEmpty(Config.Anim2))
|
||
|
{
|
||
|
serverCharacter.serverAnimationHandler.NetworkAnimator.SetTrigger(Config.Anim2);
|
||
|
}
|
||
|
|
||
|
// we're done, time to teleport!
|
||
|
serverCharacter.Movement.Teleport(m_TargetSpot);
|
||
|
|
||
|
// and then swing!
|
||
|
PerformMeleeAttack(serverCharacter);
|
||
|
}
|
||
|
|
||
|
public override void Cancel(ServerCharacter serverCharacter)
|
||
|
{
|
||
|
// OtherAnimatorVariable contains the name of the cancellation trigger
|
||
|
if (!string.IsNullOrEmpty(Config.OtherAnimatorVariable))
|
||
|
{
|
||
|
serverCharacter.serverAnimationHandler.NetworkAnimator.SetTrigger(Config.OtherAnimatorVariable);
|
||
|
}
|
||
|
|
||
|
// because the client-side visualization of the action moves the character visualization around,
|
||
|
// we need to explicitly end the client-side visuals when we abort
|
||
|
serverCharacter.clientCharacter.ClientCancelActionsByPrototypeIDRpc(ActionID);
|
||
|
|
||
|
}
|
||
|
|
||
|
public override void BuffValue(BuffableValue buffType, ref float buffedValue)
|
||
|
{
|
||
|
if (TimeRunning >= Config.ExecTimeSeconds && buffType == BuffableValue.PercentDamageReceived)
|
||
|
{
|
||
|
// we suffer no damage during the "dash" (client-side pretend movement)
|
||
|
buffedValue = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void PerformMeleeAttack(ServerCharacter parent)
|
||
|
{
|
||
|
// perform a typical melee-hit. But note that we are using the Radius field for range, not the Range field!
|
||
|
IDamageable foe = MeleeAction.GetIdealMeleeFoe(Config.IsFriendly ^ parent.IsNpc,
|
||
|
parent.physicsWrapper.DamageCollider,
|
||
|
Config.Radius,
|
||
|
(Data.TargetIds != null && Data.TargetIds.Length > 0 ? Data.TargetIds[0] : 0));
|
||
|
|
||
|
if (foe != null)
|
||
|
{
|
||
|
foe.ReceiveHP(parent, -Config.Amount);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override bool OnUpdateClient(ClientCharacter clientCharacter)
|
||
|
{
|
||
|
if (m_Dashed) { return ActionConclusion.Stop; } // we're done!
|
||
|
|
||
|
return ActionConclusion.Continue;
|
||
|
}
|
||
|
}
|
||
|
}
|