gdle/Source/AttackManager.cpp

213 lines
4.6 KiB
C++

#include <StdAfx.h>
#include "AttackManager.h"
#include "WeenieObject.h"
#include "World.h"
#include "Player.h"
#include "WeenieFactory.h"
#include "Ammunition.h"
#include "CombatFormulas.h"
#include "combat/MeleeAttackEventData.h"
#include "combat/DualWieldAttackEventData.h"
#include "combat/MissileAttackEventData.h"
// TODO fix memory leak with attack data
AttackManager::AttackManager(CWeenieObject *weenie)
{
_weenie = weenie;
}
AttackManager::~AttackManager()
{
SafeDelete(_attackData);
SafeDelete(_cleanupData);
SafeDelete(_queuedAttackData);
}
void AttackManager::MarkForCleanup(CAttackEventData *data)
{
if (_cleanupData && _cleanupData != data)
{
delete _cleanupData;
}
_cleanupData = data;
}
void AttackManager::Cancel()
{
if (_attackData)
_attackData->Cancel();
}
void AttackManager::OnAttackCancelled(uint32_t error)
{
if (_attackData)
{
_weenie->NotifyAttackDone();
_weenie->DoForcedMotion(_weenie->get_minterp()->InqStyle());
_weenie->unstick_from_object();
MarkForCleanup(_attackData);
_attackData = NULL;
}
}
bool AttackManager::RepeatAttacks()
{
if (_weenie->AsPlayer())
{
CPlayerWeenie *player = (CPlayerWeenie *)_weenie;
return player->ShouldRepeatAttacks();
}
return false;
}
void AttackManager::OnAttackDone(uint32_t error)
{
if (_weenie->AsPlayer())
{
_weenie->AsPlayer()->m_Qualities.SetFloat(ATTACK_TIMESTAMP_FLOAT, Timer::cur_time);
}
//if(_weenie->_blockNewAttacksUntil < Timer::cur_time) //fix for cancelling reload animation making attacking faster
//_weenie->_blockNewAttacksUntil = Timer::cur_time + 1.0;
if (_attackData)
{
if (RepeatAttacks() && _attackData->IsValidTarget())
{
if (_queuedAttackData != NULL)
{
//we have a queued attack, change to that.
SafeDelete(_attackData);
_attackData = _queuedAttackData;
_queuedAttackData = NULL;
}
if (_attackData->ShouldNotifyAttackDone())
{
_weenie->NotifyAttackDone();
_weenie->NotifyCommenceAttack();
}
_attackData->_attack_charge_time = Timer::cur_time + (_attackData->_attack_power * _attackData->AttackTimeMod());
_attackData->_attack_speed *= _attackData->AttackSpeedMod();
_attackData->Begin();
}
else
{
_weenie->NotifyAttackDone();
if (_weenie->_IsPlayer())
_weenie->AsPlayer()->m_bCancelAttack = true;
MarkForCleanup(_attackData);
_attackData = NULL;
}
}
}
void AttackManager::Update()
{
if (_attackData)
{
_attackData->Update();
}
SafeDelete(_cleanupData);
}
void AttackManager::OnDeath(uint32_t killer_id)
{
Cancel();
}
void AttackManager::HandleMoveToDone(uint32_t error)
{
if (_attackData)
{
_attackData->HandleMoveToDone(error);
}
}
void AttackManager::HandleAttackHook(const AttackCone &cone)
{
if (_attackData)
{
_attackData->HandleAttackHook(cone);
}
}
void AttackManager::OnMotionDone(uint32_t motion, BOOL success)
{
if (_attackData)
{
_attackData->OnMotionDone(motion, success);
if (motion == Motion_Reload)
{
_weenie->NotifyAttackDone();
_weenie->NotifyCommenceAttack();
}
}
}
bool AttackManager::IsAttacking()
{
return _attackData != NULL ? true : false;
}
void AttackManager::BeginAttack(CAttackEventData *data)
{
if (_attackData != NULL)
{
//we're already attacking, queue this, or change current queued attack to this.
SafeDelete(_queuedAttackData);
_queuedAttackData = data;
}
else
{
_attackData = data;
_attackData->Begin();
}
}
void AttackManager::BeginMeleeAttack(uint32_t target_id, ATTACK_HEIGHT height, float power, float chase_distance, uint32_t motion)
{
CMeleeAttackEvent *attackEvent = nullptr;
CWeenieObject *left = _weenie->GetWieldedCombat(COMBAT_USE_OFFHAND);
if (_weenie->GetWieldedCombat(COMBAT_USE_TWO_HANDED))
attackEvent = new CTwoHandAttackEvent();
else if (left && left->InqIntQuality(LOCATIONS_INT, 0) != SHIELD_LOC)
attackEvent = new CDualWieldAttackEvent();
else
attackEvent = new CMeleeAttackEvent();
attackEvent->_weenie = _weenie;
attackEvent->_manager = this;
attackEvent->_target_id = target_id;
attackEvent->_attack_height = height;
attackEvent->_attack_power = power;
attackEvent->_do_attack_animation = motion;
attackEvent->_fail_distance = chase_distance;
BeginAttack(attackEvent);
}
void AttackManager::BeginMissileAttack(uint32_t target_id, ATTACK_HEIGHT height, float power, uint32_t motion)
{
CMissileAttackEvent *attackEvent = new CMissileAttackEvent();
attackEvent->_weenie = _weenie;
attackEvent->_manager = this;
attackEvent->_target_id = target_id;
attackEvent->_attack_height = height;
attackEvent->_attack_power = power;
attackEvent->_do_attack_animation = motion;
BeginAttack(attackEvent);
}