gdle/Source/Ammunition.cpp
Morosity d3cbe1395c Combat method refactoring
Single method for attacks
Added combat stance mods
Added logging off modifier to defense
Added jumping penalty to defense
Reduced method duplication
Fixed DF proc on untrained
2019-09-29 01:52:19 +00:00

297 lines
8.7 KiB
C++

#include <StdAfx.h>
#include "WeenieObject.h"
#include "Ammunition.h"
#include "Player.h"
#include "World.h"
#include "CombatFormulas.h"
CAmmunitionWeenie::CAmmunitionWeenie()
{
}
CAmmunitionWeenie::~CAmmunitionWeenie()
{
}
void CAmmunitionWeenie::ApplyQualityOverrides()
{
CWeenieObject::ApplyQualityOverrides();
}
void CAmmunitionWeenie::MakeIntoMissile()
{
int stackSize = 0;
if (m_Qualities.InqInt(STACK_SIZE_INT, stackSize))
{
SetStackSize(1);
}
m_Qualities.SetInstanceID(WIELDER_IID, 0);
m_Qualities.SetInstanceID(CONTAINER_IID, 0);
_cachedHasOwner = false;
m_Qualities.SetInt(CURRENT_WIELDED_LOCATION_INT, 0);
m_Qualities.SetInt(PARENT_LOCATION_INT, 0);
m_PhysicsState = INELASTIC_PS | GRAVITY_PS | PATHCLIPPED_PS | ALIGNPATH_PS | MISSILE_PS | REPORT_COLLISIONS_PS;
SetInitialPhysicsState(m_PhysicsState);
SetPlacementFrame(Placement::MissileFlight, FALSE);
}
void CAmmunitionWeenie::MakeIntoAmmo()
{
set_state(INELASTIC_PS | GRAVITY_PS | IGNORE_COLLISIONS_PS | ETHEREAL_PS, m_bWorldIsAware ? TRUE : FALSE);
SetInitialPhysicsState(m_PhysicsState);
SetPlacementFrame(Placement::Resting, TRUE);
_timeToRot = Timer::cur_time + 1.0;
_beganRot = false;
m_Qualities.SetFloat(TIME_TO_ROT_FLOAT, _timeToRot);
}
void CAmmunitionWeenie::PostSpawn()
{
CWeenieObject::PostSpawn();
if (m_PhysicsState & MISSILE_PS)
{
EmitEffect(PS_Launch, 0.0f);
}
}
void CAmmunitionWeenie::HandleNonTargetCollision()
{
Movement_UpdatePos();
MakeIntoAmmo();
_targetID = 0;
if (CWeenieObject *source = g_pWorld->FindObject(_sourceID))
{
if (source->AsPlayer())
source->SendText("Your missile attack hit the environment.", LTT_DEFAULT);
else
MarkForDestroy();
EmitSound(Sound_Collision, 1.0f);
}
// set the collision angle to be the heading of the object?
}
void CAmmunitionWeenie::HandleTargetCollision()
{
MarkForDestroy();
}
BOOL CAmmunitionWeenie::DoCollision(const class EnvCollisionProfile &prof)
{
HandleNonTargetCollision();
return CWeenieObject::DoCollision(prof);
}
BOOL CAmmunitionWeenie::DoCollision(const class AtkCollisionProfile &prof)
{
bool targetCollision = false;
CWeenieObject *pHit = g_pWorld->FindWithinPVS(this, prof.id);
if (pHit && (!_targetID || _targetID == pHit->GetID()) && (pHit->GetID() != _sourceID) && (pHit->GetID() != _launcherID))
{
CWeenieObject *pSource = g_pWorld->FindObject(_sourceID);
if (!pHit->ImmuneToDamage(pSource))
{
targetCollision = true;
int preVarianceDamage;
float variance;
CWeenieObject *weapon = g_pWorld->FindObject(_launcherID);
// For thrown weaps, the weapon no longer exists on the last missile in a stack. So for these we will just use the cloned ammo weenie itself.
if (!weapon && m_Qualities.GetInt(DEFAULT_COMBAT_STYLE_INT, 0) == ThrownWeapon_CombatStyle)
weapon = g_pWorld->FindObject(id);
if (weapon)
{
bool bEvaded = false;
uint32_t missileDefense = 0;
if (pHit->InqSkill(MISSILE_DEFENSE_SKILL, missileDefense, FALSE) && missileDefense > 0)
{
if (pHit->TryAttackEvade((uint32_t)(_weaponSkillLevel * (_attackPower + 0.5f)), STypeSkill::MISSILE_DEFENSE_SKILL))
{
pHit->OnEvadeAttack(pSource);
// send evasion message
BinaryWriter attackerEvadeEvent;
attackerEvadeEvent.Write<uint32_t>(0x01B3);
attackerEvadeEvent.WriteString(pHit->GetName());
if (pSource != nullptr)
pSource->SendNetMessage(&attackerEvadeEvent, PRIVATE_MSG, TRUE, FALSE);
BinaryWriter attackedEvadeEvent;
attackedEvadeEvent.Write<uint32_t>(0x01B4);
if (pSource != nullptr)
attackedEvadeEvent.WriteString(pSource->GetName());
else
attackedEvadeEvent.WriteString("Unknown");
pHit->SendNetMessage(&attackedEvadeEvent, PRIVATE_MSG, TRUE, FALSE);
bEvaded = true;
}
}
if (!bEvaded)
{
EmitSound(Sound_Collision, 1.0f);
if (pSource != nullptr && pSource && pHit && pSource->AsPlayer() && pHit->AsPlayer())
{
pSource->AsPlayer()->UpdatePKActivity();
pHit->AsPlayer()->UpdatePKActivity();
}
bool isThrownWeapon = (weapon->InqIntQuality(DEFAULT_COMBAT_STYLE_INT, 0) == ThrownWeapon_CombatStyle);
preVarianceDamage = isThrownWeapon ? weapon->GetAttackDamage() : GetAttackDamage();
variance = InqFloatQuality(DAMAGE_VARIANCE_FLOAT, 0.0f);
//int elementalDamageBonus = weapon->InqDamageType() == InqDamageType() || InqDamageType() == BASE_DAMAGE_TYPE ? weapon->InqIntQuality(ELEMENTAL_DAMAGE_BONUS_INT, 0) : 0;
double damageMod = weapon->InqFloatQuality(DAMAGE_MOD_FLOAT, 1.0);
//preVarianceDamage += elementalDamageBonus;
preVarianceDamage *= damageMod;
DamageEventData dmgEvent;
dmgEvent.source = pSource;
dmgEvent.target = pHit;
dmgEvent.weapon = weapon;
dmgEvent.damage_form = DF_MISSILE;
if (InqDamageType() != BASE_DAMAGE_TYPE)
dmgEvent.damage_type = InqDamageType();
else if (!weapon->InqDamageType())
dmgEvent.damage_type = PIERCE_DAMAGE_TYPE;
else
dmgEvent.damage_type = weapon->InqDamageType();
dmgEvent.hit_quadrant = (DAMAGE_QUADRANT)prof.location;
dmgEvent.attackSkill = _weaponSkill;
dmgEvent.attackSkillLevel = _weaponSkillLevel;
dmgEvent.preVarianceDamage = preVarianceDamage;
dmgEvent.baseDamage = preVarianceDamage * (1.0f - Random::GenFloat(0.0f, variance));
CalculateCriticalHitData(&dmgEvent, NULL);
dmgEvent.wasCrit = (Random::GenFloat(0.0, 1.0) < dmgEvent.critChance) ? true : false;
if (dmgEvent.wasCrit)
{
dmgEvent.baseDamage = dmgEvent.preVarianceDamage;//Recalculate baseDamage with no variance (uses max dmg on weapon)
}
CalculateAttackConditions(&dmgEvent, _attackPower, HeadingFrom(pHit, false));
//cast on strike
if (weapon->InqDIDQuality(PROC_SPELL_DID, 0))
{
double procChance = weapon->InqFloatQuality(PROC_SPELL_RATE_FLOAT, 0.0f);
bool proc = (Random::GenFloat(0.0, 1.0) < procChance) ? true : false;
if (proc && _targetID)
{
uint32_t targetid = _targetID;
uint32_t procspell = weapon->InqDIDQuality(PROC_SPELL_DID, 0);
weapon->TryCastSpell(targetid, procspell);
}
}
uint32_t dirtyFighting = 0;
if (pSource && pSource->AsPlayer() && pSource->InqSkill(DIRTY_FIGHTING_SKILL, dirtyFighting, FALSE) && dirtyFighting > 0)
{
double skillCalc = (double)dirtyFighting / (double)dmgEvent.attackSkillLevel;
double chanceOfDfEffect = .25 * min(1.0, skillCalc);
double procRoll = Random::GenFloat(0.0, 1.0);
bool proc = (procRoll < chanceOfDfEffect) ? true : false;
SKILL_ADVANCEMENT_CLASS sac = SKILL_ADVANCEMENT_CLASS::UNTRAINED_SKILL_ADVANCEMENT_CLASS;
bool hasQuality = pSource->m_Qualities.InqSkillAdvancementClass((STypeSkill)DIRTY_FIGHTING_SKILL, sac);
uint32_t targetid = pHit->GetID();
//_weenie->AsPlayer()->SendText(csprintf("Attack Skill: %u DF Skill: %u Skill Calc: %f Proc %f", dmgEvent.attackSkillLevel, dirtyFighting, skillCalc, procRoll), LTT_COMBAT);
if (proc)
{
if (dmgEvent.hit_quadrant & DAMAGE_QUADRANT::DQ_HIGH)
{
if (sac == SPECIALIZED_SKILL_ADVANCEMENT_CLASS)
{
dmgEvent.weapon->TryCastSpell(targetid, 5938); //Blinding Assault
dmgEvent.weapon->TryCastSpell(targetid, 5941); //Traumatic Assault
}
else
{
dmgEvent.weapon->TryCastSpell(targetid, 5942); //Blinding Blow
dmgEvent.weapon->TryCastSpell(targetid, 5945); //Traumatic Blow
}
}
else if (dmgEvent.hit_quadrant & DAMAGE_QUADRANT::DQ_MEDIUM)
{
if (sac == SPECIALIZED_SKILL_ADVANCEMENT_CLASS)
{
dmgEvent.weapon->TryCastSpell(targetid, 5939); //Bleeding Assault
}
else
{
dmgEvent.weapon->TryCastSpell(targetid, 5943); //Bleeding Blow
}
}
else if (dmgEvent.hit_quadrant & DAMAGE_QUADRANT::DQ_LOW)
{
if (sac == SPECIALIZED_SKILL_ADVANCEMENT_CLASS)
{
dmgEvent.weapon->TryCastSpell(targetid, 5940); //Unbalancing Assault
}
else
{
dmgEvent.weapon->TryCastSpell(targetid, 5944); //Unbalancing Blow
}
}
else
{
SERVER_ERROR << "Unknown error on Dirty Fighting";
}
}
}
CalculateDamage(&dmgEvent);
if (pSource != nullptr)
pSource->TryToDealDamage(dmgEvent);
}
}
}
}
if (targetCollision)
HandleTargetCollision();
else
HandleNonTargetCollision();
return CWeenieObject::DoCollision(prof);
}
BOOL CAmmunitionWeenie::DoCollision(const class ObjCollisionProfile &prof)
{
HandleNonTargetCollision();
return CWeenieObject::DoCollision(prof);
}
void CAmmunitionWeenie::DoCollisionEnd(uint32_t object_id)
{
CWeenieObject::DoCollisionEnd(object_id);
}