DarkflameServer/dGame/dBehaviors/Behavior.cpp

504 lines
14 KiB
C++
Raw Permalink Normal View History

2022-08-06 03:01:59 +00:00
#include <sstream>
#include <algorithm>
#include "Behavior.h"
#include "CDActivitiesTable.h"
#include "Game.h"
#include "Logger.h"
#include "BehaviorTemplate.h"
#include "BehaviorBranchContext.h"
#include <unordered_map>
/*
* Behavior includes
*/
#include "AirMovementBehavior.h"
#include "EmptyBehavior.h"
#include "MovementSwitchBehavior.h"
#include "AndBehavior.h"
#include "AreaOfEffectBehavior.h"
#include "DurationBehavior.h"
#include "TacArcBehavior.h"
#include "LootBuffBehavior.h"
#include "AttackDelayBehavior.h"
#include "BasicAttackBehavior.h"
#include "ChainBehavior.h"
#include "ChargeUpBehavior.h"
#include "GameMessages.h"
#include "HealBehavior.h"
#include "ImaginationBehavior.h"
#include "KnockbackBehavior.h"
#include "NpcCombatSkillBehavior.h"
#include "StartBehavior.h"
#include "StunBehavior.h"
#include "ProjectileAttackBehavior.h"
#include "RepairBehavior.h"
#include "SwitchBehavior.h"
#include "SwitchMultipleBehavior.h"
#include "TargetCasterBehavior.h"
#include "VerifyBehavior.h"
#include "BuffBehavior.h"
#include "TauntBehavior.h"
#include "SkillCastFailedBehavior.h"
#include "SpawnBehavior.h"
#include "ForceMovementBehavior.h"
#include "RemoveBuffBehavior.h"
#include "ImmunityBehavior.h"
#include "InterruptBehavior.h"
#include "PlayEffectBehavior.h"
#include "DamageAbsorptionBehavior.h"
#include "VentureVisionBehavior.h"
#include "PropertyTeleportBehavior.h"
#include "BlockBehavior.h"
#include "ClearTargetBehavior.h"
#include "PullToPointBehavior.h"
#include "EndBehavior.h"
#include "ChangeOrientationBehavior.h"
#include "OverTimeBehavior.h"
#include "ApplyBuffBehavior.h"
#include "CarBoostBehavior.h"
#include "SkillEventBehavior.h"
#include "SpeedBehavior.h"
#include "DamageReductionBehavior.h"
#include "JetPackBehavior.h"
#include "FallSpeedBehavior.h"
#include "ChangeIdleFlagsBehavior.h"
#include "DarkInspirationBehavior.h"
#include "ConsumeItemBehavior.h"
2022-07-28 13:39:57 +00:00
//CDClient includes
#include "CDBehaviorParameterTable.h"
#include "CDClientDatabase.h"
#include "CDClientManager.h"
//Other includes
#include "EntityManager.h"
#include "RenderComponent.h"
#include "DestroyableComponent.h"
#include "CDBehaviorTemplateTable.h"
std::unordered_map<uint32_t, Behavior*> Behavior::Cache = {};
CDBehaviorParameterTable* Behavior::BehaviorParameterTable = nullptr;
2022-07-28 13:39:57 +00:00
Behavior* Behavior::GetBehavior(const uint32_t behaviorId) {
if (BehaviorParameterTable == nullptr) {
BehaviorParameterTable = CDClientManager::GetTable<CDBehaviorParameterTable>();
}
const auto pair = Cache.find(behaviorId);
2022-07-28 13:39:57 +00:00
if (pair == Cache.end()) {
return nullptr;
}
return static_cast<Behavior*>(pair->second);
}
2022-07-28 13:39:57 +00:00
Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) {
auto* cached = GetBehavior(behaviorId);
2022-07-28 13:39:57 +00:00
if (cached != nullptr) {
return cached;
}
2022-07-28 13:39:57 +00:00
if (behaviorId == 0) {
return new EmptyBehavior(0);
}
const auto templateId = GetBehaviorTemplate(behaviorId);
Behavior* behavior = nullptr;
2022-07-28 13:39:57 +00:00
switch (templateId) {
case BehaviorTemplate::EMPTY: break;
case BehaviorTemplate::BASIC_ATTACK:
behavior = new BasicAttackBehavior(behaviorId);
break;
case BehaviorTemplate::TAC_ARC:
behavior = new TacArcBehavior(behaviorId);
break;
case BehaviorTemplate::AND:
behavior = new AndBehavior(behaviorId);
break;
case BehaviorTemplate::PROJECTILE_ATTACK:
behavior = new ProjectileAttackBehavior(behaviorId);
break;
case BehaviorTemplate::HEAL:
behavior = new HealBehavior(behaviorId);
break;
case BehaviorTemplate::MOVEMENT_SWITCH:
behavior = new MovementSwitchBehavior(behaviorId);
break;
case BehaviorTemplate::AREA_OF_EFFECT:
behavior = new AreaOfEffectBehavior(behaviorId);
break;
case BehaviorTemplate::PLAY_EFFECT:
behavior = new PlayEffectBehavior(behaviorId);
break;
case BehaviorTemplate::IMMUNITY:
behavior = new ImmunityBehavior(behaviorId);
break;
case BehaviorTemplate::DAMAGE_BUFF: break;
case BehaviorTemplate::DAMAGE_ABSORBTION:
behavior = new DamageAbsorptionBehavior(behaviorId);
break;
case BehaviorTemplate::OVER_TIME:
behavior = new OverTimeBehavior(behaviorId);
break;
case BehaviorTemplate::IMAGINATION:
behavior = new ImaginationBehavior(behaviorId);
break;
case BehaviorTemplate::TARGET_CASTER:
behavior = new TargetCasterBehavior(behaviorId);
break;
case BehaviorTemplate::STUN:
behavior = new StunBehavior(behaviorId);
break;
case BehaviorTemplate::DURATION:
behavior = new DurationBehavior(behaviorId);
break;
case BehaviorTemplate::KNOCKBACK:
behavior = new KnockbackBehavior(behaviorId);
break;
case BehaviorTemplate::ATTACK_DELAY:
behavior = new AttackDelayBehavior(behaviorId);
break;
case BehaviorTemplate::CAR_BOOST:
behavior = new CarBoostBehavior(behaviorId);
break;
case BehaviorTemplate::FALL_SPEED:
behavior = new FallSpeedBehavior(behaviorId);
break;
case BehaviorTemplate::SHIELD: break;
case BehaviorTemplate::REPAIR_ARMOR:
behavior = new RepairBehavior(behaviorId);
break;
case BehaviorTemplate::SPEED:
behavior = new SpeedBehavior(behaviorId);
break;
case BehaviorTemplate::DARK_INSPIRATION:
behavior = new DarkInspirationBehavior(behaviorId);
break;
case BehaviorTemplate::LOOT_BUFF:
behavior = new LootBuffBehavior(behaviorId);
break;
case BehaviorTemplate::VENTURE_VISION:
behavior = new VentureVisionBehavior(behaviorId);
break;
case BehaviorTemplate::SPAWN_OBJECT:
behavior = new SpawnBehavior(behaviorId);
break;
case BehaviorTemplate::LAY_BRICK: break;
case BehaviorTemplate::SWITCH:
behavior = new SwitchBehavior(behaviorId);
break;
case BehaviorTemplate::BUFF:
behavior = new BuffBehavior(behaviorId);
break;
case BehaviorTemplate::JETPACK:
behavior = new JetPackBehavior(behaviorId);
break;
case BehaviorTemplate::SKILL_EVENT:
behavior = new SkillEventBehavior(behaviorId);
break;
case BehaviorTemplate::CONSUME_ITEM:
behavior = new ConsumeItemBehavior(behaviorId);
break;
case BehaviorTemplate::SKILL_CAST_FAILED:
behavior = new SkillCastFailedBehavior(behaviorId);
break;
case BehaviorTemplate::IMITATION_SKUNK_STINK: break;
case BehaviorTemplate::CHANGE_IDLE_FLAGS:
behavior = new ChangeIdleFlagsBehavior(behaviorId);
break;
case BehaviorTemplate::APPLY_BUFF:
behavior = new ApplyBuffBehavior(behaviorId);
break;
case BehaviorTemplate::CHAIN:
behavior = new ChainBehavior(behaviorId);
break;
case BehaviorTemplate::CHANGE_ORIENTATION:
behavior = new ChangeOrientationBehavior(behaviorId);
break;
case BehaviorTemplate::FORCE_MOVEMENT:
behavior = new ForceMovementBehavior(behaviorId);
break;
case BehaviorTemplate::INTERRUPT:
behavior = new InterruptBehavior(behaviorId);
break;
case BehaviorTemplate::ALTER_COOLDOWN: break;
case BehaviorTemplate::CHARGE_UP:
behavior = new ChargeUpBehavior(behaviorId);
break;
case BehaviorTemplate::SWITCH_MULTIPLE:
behavior = new SwitchMultipleBehavior(behaviorId);
break;
case BehaviorTemplate::START:
behavior = new StartBehavior(behaviorId);
break;
case BehaviorTemplate::END:
behavior = new EndBehavior(behaviorId);
break;
case BehaviorTemplate::ALTER_CHAIN_DELAY: break;
case BehaviorTemplate::CAMERA: break;
case BehaviorTemplate::REMOVE_BUFF:
behavior = new RemoveBuffBehavior(behaviorId);
break;
case BehaviorTemplate::GRAB: break;
case BehaviorTemplate::MODULAR_BUILD: break;
case BehaviorTemplate::NPC_COMBAT_SKILL:
behavior = new NpcCombatSkillBehavior(behaviorId);
break;
case BehaviorTemplate::BLOCK:
behavior = new BlockBehavior(behaviorId);
break;
case BehaviorTemplate::VERIFY:
behavior = new VerifyBehavior(behaviorId);
break;
case BehaviorTemplate::TAUNT:
behavior = new TauntBehavior(behaviorId);
break;
case BehaviorTemplate::AIR_MOVEMENT:
behavior = new AirMovementBehavior(behaviorId);
break;
case BehaviorTemplate::SPAWN_QUICKBUILD:
behavior = new SpawnBehavior(behaviorId);
break;
case BehaviorTemplate::PULL_TO_POINT:
behavior = new PullToPointBehavior(behaviorId);
break;
case BehaviorTemplate::PROPERTY_ROTATE: break;
case BehaviorTemplate::DAMAGE_REDUCTION:
behavior = new DamageReductionBehavior(behaviorId);
break;
case BehaviorTemplate::PROPERTY_TELEPORT:
behavior = new PropertyTeleportBehavior(behaviorId);
break;
case BehaviorTemplate::PROPERTY_CLEAR_TARGET:
behavior = new ClearTargetBehavior(behaviorId);
break;
case BehaviorTemplate::TAKE_PICTURE: break;
case BehaviorTemplate::MOUNT: break;
case BehaviorTemplate::SKILL_SET: break;
default:
//LOG("Failed to load behavior with invalid template id (%i)!", templateId);
break;
}
2022-07-28 13:39:57 +00:00
if (behavior == nullptr) {
//LOG("Failed to load unimplemented template id (%i)!", templateId);
behavior = new EmptyBehavior(behaviorId);
}
behavior->Load();
return behavior;
}
BehaviorTemplate Behavior::GetBehaviorTemplate(const uint32_t behaviorId) {
auto behaviorTemplateTable = CDClientManager::GetTable<CDBehaviorTemplateTable>();
BehaviorTemplate templateID = BehaviorTemplate::EMPTY;
// Find behavior template by its behavior id. Default to 0.
if (behaviorTemplateTable) {
auto templateEntry = behaviorTemplateTable->GetByBehaviorID(behaviorId);
if (templateEntry.behaviorID == behaviorId) {
templateID = static_cast<BehaviorTemplate>(templateEntry.templateID);
}
}
if (templateID == BehaviorTemplate::EMPTY && behaviorId != 0) {
LOG("Failed to load behavior template with id (%i)!", behaviorId);
}
return templateID;
}
// For use with enemies, to display the correct damage animations on the players
2022-07-28 13:39:57 +00:00
void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID secondary) {
auto* targetEntity = Game::entityManager->GetEntity(target);
2022-07-28 13:39:57 +00:00
if (targetEntity == nullptr) {
return;
}
const auto effectId = this->m_effectId;
2022-07-28 13:39:57 +00:00
if (effectId == 0) {
GameMessages::SendPlayFXEffect(targetEntity, -1, type, "", secondary, 1, 1, true);
return;
}
auto* renderComponent = targetEntity->GetComponent<RenderComponent>();
const auto typeString = GeneralUtils::UTF16ToWTF8(type);
const auto itr = m_effectNames.find(typeString);
if (type.empty()) {
type = GeneralUtils::ASCIIToUTF16(m_effectType);
}
if (itr != m_effectNames.end()) {
if (renderComponent == nullptr) {
GameMessages::SendPlayFXEffect(targetEntity, effectId, type, itr->second, secondary, 1, 1, true);
return;
}
renderComponent->PlayEffect(effectId, type, itr->second, secondary);
return;
}
// The SQlite result object becomes invalid if the query object leaves scope.
// So both queries are defined before the if statement
CppSQLite3Query result;
auto typeQuery = CDClientDatabase::CreatePreppedStmt(
"SELECT effectName FROM BehaviorEffect WHERE effectType = ? AND effectID = ?;");
auto idQuery = CDClientDatabase::CreatePreppedStmt(
"SELECT effectName, effectType FROM BehaviorEffect WHERE effectID = ?;");
if (!type.empty()) {
typeQuery.bind(1, typeString.c_str());
typeQuery.bind(2, static_cast<int>(effectId));
result = typeQuery.execQuery();
} else {
idQuery.bind(1, static_cast<int>(effectId));
result = idQuery.execQuery();
}
2022-07-28 13:39:57 +00:00
if (result.eof() || result.fieldIsNull(0)) {
return;
}
const auto name = std::string(result.getStringField("effectName"));
2022-07-28 13:39:57 +00:00
if (type.empty()) {
const auto typeResult = result.getStringField("effectType");
type = GeneralUtils::ASCIIToUTF16(typeResult);
m_effectType = typeResult;
}
result.finalize();
m_effectNames.insert_or_assign(typeString, name);
2022-07-28 13:39:57 +00:00
if (renderComponent == nullptr) {
GameMessages::SendPlayFXEffect(targetEntity, effectId, type, name, secondary, 1, 1, true);
return;
}
renderComponent->PlayEffect(effectId, type, name, secondary);
}
2022-07-28 13:39:57 +00:00
Behavior::Behavior(const uint32_t behaviorId) {
auto behaviorTemplateTable = CDClientManager::GetTable<CDBehaviorTemplateTable>();
Remove memory leak in player container and warning in Behavior (#640) * Add friends list migration * Change friends to use charID Update friends table to use charID and not LWOOBJID variant. * Fix remove friend Fix remove friend and make the query more readable at a glance. * Add and remove friends in the container Properly add and remove friends in the player container * add enums * Add best friends and basic GM support V1 * Add more features * not online / doesnt exist implementation Implements the not online and invalid character response codes * Address players not being removed Fix an issue where players would not be marked as offline in the friends list due to the message not being sent in all circumstances. Tested changes on 3 clients, switching characters, logging out from character select, switching characters, world transfer and my friends list looked as it was supposed to. * Implement proper friends system Remove debug logs Track count of best friends Add best friends list cap of 5 Add config option and best friend update Add a config option and implement the last missing best friend serialization Added comments and fixed remove best friend bug Added some comments and addressed an issue where removing best friends would not remove them from your internal count of friends. properties and logs fixes whoops, had an issue send reply if already BFFs Send the correct objectID I really need to rename these Fix white space goon * Replace queries with unique ptrs * remove user from player container on deletion Remove the user from the player container when they delete their character. * Bump patch version * Improvements to PlayerContainer Resolved a memory leak in the player container, removed commented out code and resolved a warning in Behavior.cpp * Make it a unique ptr * Improvements to PlayerContainer Resolved a memory leak in the player container, removed commented out code and resolved a warning in Behavior.cpp Make it a unique ptr * Update PlayerContainer.cpp
2022-07-13 16:11:24 +00:00
CDBehaviorTemplate templateInDatabase{};
if (behaviorTemplateTable) {
auto templateEntry = behaviorTemplateTable->GetByBehaviorID(behaviorId);
if (templateEntry.behaviorID == behaviorId) {
templateInDatabase = templateEntry;
}
}
this->m_behaviorId = behaviorId;
// Add to cache
Cache.insert_or_assign(behaviorId, this);
if (behaviorId == 0) {
this->m_effectId = 0;
this->m_templateId = BehaviorTemplate::EMPTY;
}
// Make sure we do not proceed if we are trying to load an invalid behavior
2022-07-28 13:39:57 +00:00
if (templateInDatabase.behaviorID == 0) {
LOG("Failed to load behavior with id (%i)!", behaviorId);
this->m_effectId = 0;
this->m_templateId = BehaviorTemplate::EMPTY;
return;
}
this->m_templateId = static_cast<BehaviorTemplate>(templateInDatabase.templateID);
this->m_effectId = templateInDatabase.effectID;
this->m_effectHandle = *templateInDatabase.effectHandle;
}
2022-07-28 13:39:57 +00:00
float Behavior::GetFloat(const std::string& name, const float defaultValue) const {
// Get the behavior parameter entry and return its value.
if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::GetTable<CDBehaviorParameterTable>();
return BehaviorParameterTable->GetValue(this->m_behaviorId, name, defaultValue);
}
2022-07-28 13:39:57 +00:00
bool Behavior::GetBoolean(const std::string& name, const bool defaultValue) const {
return GetFloat(name, defaultValue) > 0;
}
2022-07-28 13:39:57 +00:00
int32_t Behavior::GetInt(const std::string& name, const int defaultValue) const {
return static_cast<int32_t>(GetFloat(name, defaultValue));
}
2022-07-28 13:39:57 +00:00
Behavior* Behavior::GetAction(const std::string& name) const {
const auto id = GetInt(name);
return CreateBehavior(id);
}
2022-07-28 13:39:57 +00:00
Behavior* Behavior::GetAction(float value) const {
return CreateBehavior(static_cast<int32_t>(value));
}
2022-07-28 13:39:57 +00:00
std::map<std::string, float> Behavior::GetParameterNames() const {
std::map<std::string, float> templatesInDatabase;
// Find behavior template by its behavior id.
if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::GetTable<CDBehaviorParameterTable>();
if (BehaviorParameterTable) {
templatesInDatabase = BehaviorParameterTable->GetParametersByBehaviorID(this->m_behaviorId);
}
return templatesInDatabase;
}
2022-07-28 13:39:57 +00:00
void Behavior::Load() {
}
void Behavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) {
}
void Behavior::Sync(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) {
}
2022-07-28 13:39:57 +00:00
void Behavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
}
2022-07-28 13:39:57 +00:00
void Behavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) {
}
2022-07-28 13:39:57 +00:00
void Behavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) {
}
void Behavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) {
}
void Behavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) {
}