2019-07-07 20:56:15 +00:00
|
|
|
#include <StdAfx.h>
|
2018-11-09 13:39:05 -06:00
|
|
|
#include "AttackManager.h"
|
|
|
|
|
#include "WeenieObject.h"
|
|
|
|
|
#include "World.h"
|
|
|
|
|
#include "Player.h"
|
|
|
|
|
#include "WeenieFactory.h"
|
|
|
|
|
#include "Ammunition.h"
|
|
|
|
|
#include "CombatFormulas.h"
|
|
|
|
|
|
|
|
|
|
// TODO fix memory leak with attack data
|
|
|
|
|
|
|
|
|
|
CAttackEventData::CAttackEventData() noexcept
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CAttackEventData::Update()
|
|
|
|
|
{
|
|
|
|
|
if (_attack_charge_time >= 0.0 && Timer::cur_time >= _attack_charge_time)
|
|
|
|
|
{
|
|
|
|
|
PostCharge();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CheckTimeout();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CAttackEventData::Setup()
|
|
|
|
|
{
|
|
|
|
|
_max_attack_distance = DISTANCE_REQUIRED_FOR_MELEE_ATTACK;
|
|
|
|
|
_max_attack_angle = MAX_MELEE_ATTACK_CONE_ANGLE;
|
|
|
|
|
_timeout = Timer::cur_time + 15.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CAttackEventData::PostCharge()
|
|
|
|
|
{
|
|
|
|
|
_attack_charge_time = -1.0;
|
|
|
|
|
|
|
|
|
|
if (InAttackCone())
|
|
|
|
|
{
|
|
|
|
|
OnReadyToAttack();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
MoveToAttack();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CAttackEventData::Begin()
|
|
|
|
|
{
|
|
|
|
|
Setup();
|
|
|
|
|
|
|
|
|
|
CWeenieObject *target = GetTarget();
|
|
|
|
|
if (!target)
|
|
|
|
|
{
|
|
|
|
|
Cancel(WERROR_OBJECT_GONE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (target->HasOwner())
|
|
|
|
|
{
|
|
|
|
|
Cancel(WERROR_OBJECT_GONE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!target->IsAttackable() && !_weenie->CanTarget(target))
|
|
|
|
|
{
|
|
|
|
|
Cancel();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 05:59:21 -06:00
|
|
|
if (_attack_charge_time < 0.0)
|
2018-11-09 13:39:05 -06:00
|
|
|
{
|
|
|
|
|
PostCharge();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CAttackEventData::MoveToAttack()
|
|
|
|
|
{
|
|
|
|
|
_move_to = true;
|
|
|
|
|
|
|
|
|
|
MovementParameters params;
|
|
|
|
|
params.can_walk = 0;
|
|
|
|
|
params.can_run = 0;
|
|
|
|
|
params.can_sidestep = 0;
|
|
|
|
|
params.can_walk_backwards = 0;
|
|
|
|
|
params.move_away = 1;
|
|
|
|
|
params.can_charge = m_bCanCharge || !_weenie->AsPlayer() ? 1 : 0;
|
|
|
|
|
params.fail_walk = 1;
|
|
|
|
|
params.use_final_heading = 1;
|
|
|
|
|
params.sticky = _use_sticky;
|
|
|
|
|
|
|
|
|
|
params.min_distance = 0.1f;
|
|
|
|
|
params.distance_to_object = _max_attack_distance - 0.5f; // 0.5
|
|
|
|
|
params.fail_distance = _fail_distance;
|
|
|
|
|
params.speed = 1.5f;
|
|
|
|
|
params.action_stamp = ++_weenie->m_wAnimSequence;
|
|
|
|
|
_weenie->last_move_was_autonomous = false;
|
|
|
|
|
_weenie->MoveToObject(_target_id, ¶ms);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CAttackEventData::TurnToAttack()
|
|
|
|
|
{
|
|
|
|
|
_move_to = true;
|
|
|
|
|
|
|
|
|
|
MovementParameters params;
|
|
|
|
|
|
|
|
|
|
_weenie->last_move_was_autonomous = false;
|
|
|
|
|
|
|
|
|
|
_weenie->TurnToObject(_target_id, ¶ms);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CAttackEventData::CheckTimeout()
|
|
|
|
|
{
|
|
|
|
|
if (Timer::cur_time > _timeout)
|
|
|
|
|
{
|
|
|
|
|
if (_move_to)
|
|
|
|
|
Cancel(WERROR_MOVED_TOO_FAR);
|
|
|
|
|
else
|
|
|
|
|
Cancel(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
void CAttackEventData::Cancel(uint32_t error)
|
2018-11-09 13:39:05 -06:00
|
|
|
{
|
|
|
|
|
CancelMoveTo();
|
|
|
|
|
|
|
|
|
|
_manager->OnAttackCancelled(error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CAttackEventData::CancelMoveTo()
|
|
|
|
|
{
|
|
|
|
|
if (_move_to)
|
|
|
|
|
{
|
|
|
|
|
_weenie->cancel_moveto();
|
|
|
|
|
_weenie->Animation_MoveToUpdate();
|
|
|
|
|
|
|
|
|
|
_move_to = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double CAttackEventData::DistanceToTarget()
|
|
|
|
|
{
|
|
|
|
|
if (!_target_id || _target_id == _weenie->GetID())
|
|
|
|
|
return 0.0;
|
|
|
|
|
|
|
|
|
|
CWeenieObject *target = GetTarget();
|
|
|
|
|
if (!target)
|
|
|
|
|
return FLT_MAX;
|
|
|
|
|
|
|
|
|
|
return _weenie->DistanceTo(target, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double CAttackEventData::HeadingToTarget(bool relative)
|
|
|
|
|
{
|
|
|
|
|
if (!_target_id || _target_id == _weenie->GetID())
|
|
|
|
|
return 0.0;
|
|
|
|
|
|
|
|
|
|
CWeenieObject *target = GetTarget();
|
|
|
|
|
if (!target)
|
|
|
|
|
return 0.0;
|
|
|
|
|
|
|
|
|
|
return _weenie->HeadingTo(target, relative);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CAttackEventData::InAttackRange()
|
|
|
|
|
{
|
|
|
|
|
CWeenieObject *target = GetTarget();
|
|
|
|
|
if (!target || target->HasOwner())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if ((_max_attack_distance + F_EPSILON) < DistanceToTarget())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CAttackEventData::InAttackCone()
|
|
|
|
|
{
|
|
|
|
|
CWeenieObject *target = GetTarget();
|
|
|
|
|
if (!target || target->HasOwner())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if ((_max_attack_distance + F_EPSILON) < DistanceToTarget())
|
|
|
|
|
return false;
|
|
|
|
|
if ((_max_attack_angle + F_EPSILON) < HeadingToTarget())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CWeenieObject *CAttackEventData::GetTarget()
|
|
|
|
|
{
|
|
|
|
|
return g_pWorld->FindObject(_target_id);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
void CAttackEventData::HandleMoveToDone(uint32_t error)
|
2018-11-09 13:39:05 -06:00
|
|
|
{
|
|
|
|
|
_move_to = false;
|
|
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
|
{
|
|
|
|
|
Cancel(error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!InAttackRange())
|
|
|
|
|
{
|
|
|
|
|
Cancel(WERROR_TOO_FAR);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OnReadyToAttack();
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
void CAttackEventData::OnMotionDone(uint32_t motion, BOOL success)
|
2018-11-09 13:39:05 -06:00
|
|
|
{
|
|
|
|
|
if (_move_to || _turn_to || !_active_attack_anim)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (motion == _active_attack_anim)
|
|
|
|
|
{
|
|
|
|
|
_active_attack_anim = 0;
|
|
|
|
|
|
|
|
|
|
if (success)
|
|
|
|
|
{
|
|
|
|
|
OnAttackAnimSuccess(motion);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Cancel();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
void CAttackEventData::OnAttackAnimSuccess(uint32_t motion)
|
2018-11-09 13:39:05 -06:00
|
|
|
{
|
|
|
|
|
Done();
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
void CAttackEventData::Done(uint32_t error)
|
2018-11-09 13:39:05 -06:00
|
|
|
{
|
|
|
|
|
_manager->OnAttackDone(error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CAttackEventData::IsValidTarget()
|
|
|
|
|
{
|
|
|
|
|
CWeenieObject *target = GetTarget();
|
|
|
|
|
|
|
|
|
|
if (!target || (!target->IsAttackable() && !_weenie->CanTarget(target)) || target->IsDead() || target->IsInPortalSpace() || target->ImmuneToDamage(_weenie))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
void CAttackEventData::ExecuteAnimation(uint32_t motion, MovementParameters *params)
|
2018-11-09 13:39:05 -06:00
|
|
|
{
|
|
|
|
|
assert(!_move_to);
|
|
|
|
|
assert(!_turn_to);
|
|
|
|
|
assert(!_active_attack_anim);
|
|
|
|
|
|
|
|
|
|
if (_weenie->IsDead() || _weenie->IsInPortalSpace())
|
|
|
|
|
{
|
|
|
|
|
Cancel(WERROR_ACTIONS_LOCKED);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_active_attack_anim = motion;
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t error = _weenie->DoForcedMotion(motion, params);
|
2018-11-09 13:39:05 -06:00
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
|
{
|
|
|
|
|
Cancel(error);
|
|
|
|
|
}
|
|
|
|
|
}
|