diff options
Diffstat (limited to 'src/Mobs/Behaviors/BehaviorAttacker.cpp')
-rw-r--r-- | src/Mobs/Behaviors/BehaviorAttacker.cpp | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/src/Mobs/Behaviors/BehaviorAttacker.cpp b/src/Mobs/Behaviors/BehaviorAttacker.cpp new file mode 100644 index 000000000..14ce8a264 --- /dev/null +++ b/src/Mobs/Behaviors/BehaviorAttacker.cpp @@ -0,0 +1,255 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "BehaviorAttacker.h" +#include "BehaviorStriker.h" +#include "../Monster.h" +#include "../../Entities/Pawn.h" +#include "../../Entities/Player.h" + + + +cBehaviorAttacker::cBehaviorAttacker() : + m_AttackRate(3) + , m_AttackDamage(1) + , m_AttackRange(1) + , m_AttackCoolDownTicksLeft(0) + , m_TicksSinceLastDamaged(100) +{ + +} + + + + + +void cBehaviorAttacker::AttachToMonster(cMonster & a_Parent, cBehaviorStriker & a_ParentStriker) +{ + m_Parent = &a_Parent; + m_ParentStriker = &a_ParentStriker; + m_Parent->AttachTickBehavior(this); + m_Parent->AttachDestroyBehavior(this); + m_Parent->AttachPostTickBehavior(this); + m_Parent->AttachDoTakeDamageBehavior(this); +} + + + + + +bool cBehaviorAttacker::IsControlDesired(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) +{ + UNUSED(a_Dt); + UNUSED(a_Chunk); + // If we have a target, we have something to do! Return true and control the mob Ticks. + // Otherwise return false. + return (GetTarget() != nullptr); +} + + + + + +void cBehaviorAttacker::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) +{ + UNUSED(a_Dt); + UNUSED(a_Chunk); + /* + * if ((GetTarget() != nullptr)) + { + ASSERT(GetTarget()->IsTicking()); + + if (GetTarget()->IsPlayer()) + { + if (!static_cast<cPlayer *>(GetTarget())->CanMobsTarget()) + { + SetTarget(nullptr); + } + } + } //mobTodo copied from monster.cpp + * */ + + ASSERT((GetTarget() == nullptr) || (GetTarget()->IsPawn() && (GetTarget()->GetWorld() == m_Parent->GetWorld()))); + // Stop targeting out of range targets + if (GetTarget() != nullptr) + { + if (TargetOutOfSight()) + { + SetTarget(nullptr); + } + else + { + if (TargetIsInStrikeRange()) + { + StrikeTarget(); + } + else + { + ApproachTarget(); // potential mobTodo: decoupling approaching from attacking + // Not important now, but important for future extensibility, e.g. + // cow chases wheat but using the netherman approacher to teleport around. + } + } + } +} + +void cBehaviorAttacker::ApproachTarget() +{ + m_Parent->MoveToPosition(m_Target->GetPosition()); +} + + + +void cBehaviorAttacker::PostTick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) +{ + if (m_TicksSinceLastDamaged < 100) + { + ++m_TicksSinceLastDamaged; + } + + if (m_AttackCoolDownTicksLeft > 0) + { + m_AttackCoolDownTicksLeft -= 1; + } +} + + + + + +void cBehaviorAttacker::DoTakeDamage(TakeDamageInfo & a_TDI) +{ + if ((a_TDI.Attacker != nullptr) && a_TDI.Attacker->IsPawn()) + { + if ( + (!a_TDI.Attacker->IsPlayer()) || + (static_cast<cPlayer *>(a_TDI.Attacker)->CanMobsTarget()) + ) + { + SetTarget(static_cast<cPawn*>(a_TDI.Attacker)); + } + m_TicksSinceLastDamaged = 0; + } +} + + + + + +void cBehaviorAttacker::Destroyed() +{ + SetTarget(nullptr); +} + + + + + +void cBehaviorAttacker::SetAttackRate(float a_AttackRate) +{ + m_AttackRate = a_AttackRate; +} + + + + + +void cBehaviorAttacker::SetAttackRange(int a_AttackRange) +{ + m_AttackRange = a_AttackRange; +} + + + + + +void cBehaviorAttacker::SetAttackDamage(int a_AttackDamage) +{ + m_AttackDamage = a_AttackDamage; +} + + + + +cPawn * cBehaviorAttacker::GetTarget() +{ + return m_Target; +} + + + + + +void cBehaviorAttacker::SetTarget(cPawn * a_Target) +{ + m_Target = a_Target; +} + + + + + +bool cBehaviorAttacker::TargetIsInStrikeRange() +{ + ASSERT(m_Target != nullptr); + ASSERT(m_Parent != nullptr); + /* + #include "../../Tracer.h" + cTracer LineOfSight(m_Parent->GetWorld()); + Vector3d MyHeadPosition = m_Parent->GetPosition() + Vector3d(0, m_Parent->GetHeight(), 0); + Vector3d AttackDirection(m_ParentChaser->GetTarget()->GetPosition() + Vector3d(0, GetTarget()->GetHeight(), 0) - MyHeadPosition); + + + if (GetTarget() != nullptr) + { + MoveToPosition(GetTarget()->GetPosition()); + } + if (TargetIsInRange() && !LineOfSight.Trace(MyHeadPosition, AttackDirection, static_cast<int>(AttackDirection.Length())) && (GetHealth() > 0.0)) + { + // Attack if reached destination, target isn't null, and have a clear line of sight to target (so won't attack through walls) + Attack(a_Dt); + } + */ + + return ((m_Target->GetPosition() - m_Parent->GetPosition()).SqrLength() < (m_AttackRange * m_AttackRange)); +} + + + + + +bool cBehaviorAttacker::TargetOutOfSight() +{ + ASSERT(m_Target != nullptr); + if ((GetTarget()->GetPosition() - m_Parent->GetPosition()).Length() > m_Parent->GetSightDistance()) + { + return true; + } + return false; +} + + + + + +void cBehaviorAttacker::ResetStrikeCooldown() +{ + m_AttackCoolDownTicksLeft = static_cast<int>(3 * 20 * m_AttackRate); // A second has 20 ticks, an attack rate of 1 means 1 hit every 3 seconds +} + + + + + +void cBehaviorAttacker::StrikeTarget() +{ + if (m_AttackCoolDownTicksLeft != 0) + { + cBehaviorStriker * Striker = m_ParentStriker; + if (Striker != nullptr) + { + // Striker->Strike(m_Target); //mobTodo + } + ResetStrikeCooldown(); + } +} |