2022-08-06 03:01:59 +00:00
|
|
|
#include "BasicAttackBehavior.h"
|
2021-12-05 17:54:36 +00:00
|
|
|
#include "BehaviorBranchContext.h"
|
|
|
|
#include "Game.h"
|
|
|
|
#include "dLogger.h"
|
|
|
|
#include "EntityManager.h"
|
|
|
|
#include "DestroyableComponent.h"
|
|
|
|
#include "BehaviorContext.h"
|
|
|
|
|
|
|
|
|
|
|
|
void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
|
|
|
|
if (context->unmanaged) {
|
|
|
|
auto* entity = EntityManager::Instance()->GetEntity(branch.target);
|
|
|
|
|
|
|
|
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
|
|
|
if (destroyableComponent != nullptr) {
|
|
|
|
PlayFx(u"onhit", entity->GetObjectID());
|
2022-12-16 06:10:58 +00:00
|
|
|
destroyableComponent->Damage(this->m_MaxDamage, context->originator, context->skillID);
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
|
|
|
|
2022-12-16 06:10:58 +00:00
|
|
|
this->m_OnSuccess->Handle(context, bitStream, branch);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2022-07-25 02:26:51 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
bitStream->AlignReadToByteBoundary();
|
|
|
|
|
2022-12-16 06:10:58 +00:00
|
|
|
uint16_t allocatedBits{};
|
|
|
|
if (!bitStream->Read(allocatedBits) || allocatedBits == 0) {
|
|
|
|
Game::logger->LogDebug("BasicAttackBehavior", "No allocated bits");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Game::logger->LogDebug("BasicAttackBehavior", "Number of allocated bits %i", allocatedBits);
|
2021-12-05 17:54:36 +00:00
|
|
|
const auto baseAddress = bitStream->GetReadOffset();
|
2022-12-16 06:10:58 +00:00
|
|
|
bool isBlocked{};
|
|
|
|
bool isImmune{};
|
|
|
|
bool isSuccess{};
|
|
|
|
|
|
|
|
if (!bitStream->Read(isBlocked)) {
|
|
|
|
Game::logger->LogDebug("BasicAttackBehavior", "Unable to read isBlocked");
|
2021-12-05 17:54:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-12-16 06:10:58 +00:00
|
|
|
if (isBlocked) return;
|
|
|
|
|
|
|
|
if (!bitStream->Read(isImmune)) {
|
|
|
|
Game::logger->LogDebug("BasicAttackBehavior", "Unable to read isImmune");
|
2021-12-05 17:54:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-12-16 06:10:58 +00:00
|
|
|
if (isImmune) return;
|
|
|
|
|
|
|
|
if (bitStream->Read(isSuccess) && isSuccess) { // Success
|
|
|
|
uint32_t unknown{};
|
|
|
|
if (!bitStream->Read(unknown)) {
|
|
|
|
Game::logger->LogDebug("BasicAttackBehavior", "Unable to read unknown");
|
|
|
|
return;
|
|
|
|
}
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2022-12-16 06:10:58 +00:00
|
|
|
uint32_t damageDealt{};
|
|
|
|
if (!bitStream->Read(damageDealt)) {
|
|
|
|
Game::logger->LogDebug("BasicAttackBehavior", "Unable to read damageDealt");
|
|
|
|
return;
|
|
|
|
}
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
// A value that's too large may be a cheating attempt, so we set it to MIN too
|
2022-12-16 06:10:58 +00:00
|
|
|
if (damageDealt > this->m_MaxDamage || damageDealt < this->m_MinDamage) {
|
|
|
|
damageDealt = this->m_MinDamage;
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto* entity = EntityManager::Instance()->GetEntity(branch.target);
|
2022-12-16 06:10:58 +00:00
|
|
|
bool died{};
|
|
|
|
if (!bitStream->Read(died)) {
|
|
|
|
Game::logger->LogDebug("BasicAttackBehavior", "Unable to read died");
|
|
|
|
return;
|
|
|
|
}
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
if (entity != nullptr) {
|
2022-07-28 13:39:57 +00:00
|
|
|
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
2021-12-05 17:54:36 +00:00
|
|
|
if (destroyableComponent != nullptr) {
|
|
|
|
PlayFx(u"onhit", entity->GetObjectID());
|
2022-04-25 10:25:07 +00:00
|
|
|
destroyableComponent->Damage(damageDealt, context->originator, context->skillID);
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-16 06:10:58 +00:00
|
|
|
uint8_t successState{};
|
|
|
|
if (!bitStream->Read(successState)) {
|
|
|
|
Game::logger->LogDebug("BasicAttackBehavior", "Unable to read success state");
|
|
|
|
return;
|
|
|
|
}
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
switch (successState) {
|
|
|
|
case 1:
|
2022-12-16 06:10:58 +00:00
|
|
|
this->m_OnSuccess->Handle(context, bitStream, branch);
|
2021-12-05 17:54:36 +00:00
|
|
|
break;
|
|
|
|
default:
|
2022-12-16 06:10:58 +00:00
|
|
|
Game::logger->LogDebug("BasicAttackBehavior", "Unknown success state (%i)!", successState);
|
2021-12-05 17:54:36 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bitStream->SetReadOffset(baseAddress + allocatedBits);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
|
|
|
|
auto* self = EntityManager::Instance()->GetEntity(context->originator);
|
|
|
|
if (self == nullptr) {
|
2022-12-16 06:10:58 +00:00
|
|
|
Game::logger->LogDebug("BasicAttackBehavior", "Invalid self entity (%llu)!", context->originator);
|
2021-12-05 17:54:36 +00:00
|
|
|
return;
|
|
|
|
}
|
2022-07-25 02:26:51 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
bitStream->AlignWriteToByteBoundary();
|
|
|
|
|
|
|
|
const auto allocatedAddress = bitStream->GetWriteOffset();
|
|
|
|
|
|
|
|
bitStream->Write(uint16_t(0));
|
|
|
|
|
|
|
|
const auto startAddress = bitStream->GetWriteOffset();
|
|
|
|
|
|
|
|
bitStream->Write0(); // Blocked
|
|
|
|
bitStream->Write0(); // Immune
|
|
|
|
bitStream->Write1(); // Success
|
|
|
|
|
|
|
|
if (true) {
|
|
|
|
uint32_t unknown3 = 0;
|
|
|
|
bitStream->Write(unknown3);
|
|
|
|
|
2022-12-16 06:10:58 +00:00
|
|
|
auto damage = this->m_MinDamage;
|
2021-12-05 17:54:36 +00:00
|
|
|
auto* entity = EntityManager::Instance()->GetEntity(branch.target);
|
|
|
|
|
|
|
|
if (entity == nullptr) {
|
|
|
|
damage = 0;
|
|
|
|
bitStream->Write(damage);
|
|
|
|
bitStream->Write(false);
|
|
|
|
} else {
|
|
|
|
bitStream->Write(damage);
|
|
|
|
bitStream->Write(true);
|
|
|
|
|
|
|
|
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
|
|
|
if (damage != 0 && destroyableComponent != nullptr) {
|
|
|
|
PlayFx(u"onhit", entity->GetObjectID(), 1);
|
2022-07-28 13:39:57 +00:00
|
|
|
destroyableComponent->Damage(damage, context->originator, context->skillID, false);
|
2021-12-05 17:54:36 +00:00
|
|
|
context->ScheduleUpdate(branch.target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t successState = 1;
|
|
|
|
bitStream->Write(successState);
|
|
|
|
|
|
|
|
switch (successState) {
|
|
|
|
case 1:
|
2022-12-16 06:10:58 +00:00
|
|
|
this->m_OnSuccess->Calculate(context, bitStream, branch);
|
2021-12-05 17:54:36 +00:00
|
|
|
break;
|
|
|
|
default:
|
2022-12-16 06:10:58 +00:00
|
|
|
Game::logger->LogDebug("BasicAttackBehavior", "Unknown success state (%i)!", successState);
|
2021-12-05 17:54:36 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto endAddress = bitStream->GetWriteOffset();
|
|
|
|
const uint16_t allocate = endAddress - startAddress + 1;
|
|
|
|
|
|
|
|
bitStream->SetWriteOffset(allocatedAddress);
|
|
|
|
bitStream->Write(allocate);
|
|
|
|
bitStream->SetWriteOffset(startAddress + allocate);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BasicAttackBehavior::Load() {
|
2022-12-16 06:10:58 +00:00
|
|
|
this->m_MinDamage = GetInt("min damage");
|
|
|
|
if (this->m_MinDamage == 0) this->m_MinDamage = 1;
|
|
|
|
|
|
|
|
this->m_MaxDamage = GetInt("max damage");
|
|
|
|
if (this->m_MaxDamage == 0) this->m_MaxDamage = 1;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2022-12-16 06:10:58 +00:00
|
|
|
this->m_OnSuccess = GetAction("on_success");
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2022-12-16 06:10:58 +00:00
|
|
|
this->m_OnFailArmor = GetAction("on_fail_armor");
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|