#include #include #include "Behavior.h" #include "CDActivitiesTable.h" #include "Game.h" #include "dLogger.h" #include "BehaviorTemplates.h" #include "BehaviorBranchContext.h" /* * Behavior includes */ #include "AirMovementBehavior.h" #include "EmptyBehavior.h" #include "MovementSwitchBehavior.h" #include "AndBehavior.h" #include "AreaOfEffectBehavior.h" #include "DurationBehavior.h" #include "TacArcBehavior.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 "ImmunityBehavior.h" #include "InterruptBehavior.h" #include "PlayEffectBehavior.h" #include "DamageAbsorptionBehavior.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" //CDClient includes #include "CDBehaviorParameterTable.h" #include "CDClientDatabase.h" #include "CDClientManager.h" //Other includes #include "EntityManager.h" #include "RenderComponent.h" #include "DestroyableComponent.h" std::map Behavior::Cache = {}; CDBehaviorParameterTable* Behavior::BehaviorParameterTable = nullptr; Behavior* Behavior::GetBehavior(const uint32_t behaviorId) { if (BehaviorParameterTable == nullptr) { BehaviorParameterTable = CDClientManager::Instance()->GetTable("BehaviorParameter"); } const auto pair = Cache.find(behaviorId); if (pair == Cache.end()) { return nullptr; } return static_cast(pair->second); } Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) { auto* cached = GetBehavior(behaviorId); if (cached != nullptr) { return cached; } if (behaviorId == 0) { return new EmptyBehavior(0); } const auto templateId = GetBehaviorTemplate(behaviorId); Behavior* behavior = nullptr; switch (templateId) { case BehaviorTemplates::BEHAVIOR_EMPTY: break; case BehaviorTemplates::BEHAVIOR_BASIC_ATTACK: behavior = new BasicAttackBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_TAC_ARC: behavior = new TacArcBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_AND: behavior = new AndBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_PROJECTILE_ATTACK: behavior = new ProjectileAttackBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_HEAL: behavior = new HealBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_MOVEMENT_SWITCH: behavior = new MovementSwitchBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_AREA_OF_EFFECT: behavior = new AreaOfEffectBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_PLAY_EFFECT: behavior = new PlayEffectBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_IMMUNITY: behavior = new ImmunityBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_DAMAGE_BUFF: break; case BehaviorTemplates::BEHAVIOR_DAMAGE_ABSORBTION: behavior = new DamageAbsorptionBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_OVER_TIME: behavior = new OverTimeBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_IMAGINATION: behavior = new ImaginationBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_TARGET_CASTER: behavior = new TargetCasterBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_STUN: behavior = new StunBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_DURATION: behavior = new DurationBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_KNOCKBACK: behavior = new KnockbackBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_ATTACK_DELAY: behavior = new AttackDelayBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_CAR_BOOST: behavior = new CarBoostBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_FALL_SPEED: break; case BehaviorTemplates::BEHAVIOR_SHIELD: break; case BehaviorTemplates::BEHAVIOR_REPAIR_ARMOR: behavior = new RepairBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_SPEED: behavior = new SpeedBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_DARK_INSPIRATION: break; case BehaviorTemplates::BEHAVIOR_LOOT_BUFF: break; case BehaviorTemplates::BEHAVIOR_VENTURE_VISION: break; case BehaviorTemplates::BEHAVIOR_SPAWN_OBJECT: behavior = new SpawnBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_LAY_BRICK: break; case BehaviorTemplates::BEHAVIOR_SWITCH: behavior = new SwitchBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_BUFF: behavior = new BuffBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_JETPACK: behavior = new JetPackBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_SKILL_EVENT: behavior = new SkillEventBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_CONSUME_ITEM: break; case BehaviorTemplates::BEHAVIOR_SKILL_CAST_FAILED: behavior = new SkillCastFailedBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_IMITATION_SKUNK_STINK: break; case BehaviorTemplates::BEHAVIOR_CHANGE_IDLE_FLAGS: break; case BehaviorTemplates::BEHAVIOR_APPLY_BUFF: behavior = new ApplyBuffBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_CHAIN: behavior = new ChainBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_CHANGE_ORIENTATION: behavior = new ChangeOrientationBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_FORCE_MOVEMENT: behavior = new ForceMovementBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_INTERRUPT: behavior = new InterruptBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_ALTER_COOLDOWN: break; case BehaviorTemplates::BEHAVIOR_CHARGE_UP: behavior = new ChargeUpBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_SWITCH_MULTIPLE: behavior = new SwitchMultipleBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_START: behavior = new StartBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_END: behavior = new EndBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_ALTER_CHAIN_DELAY: break; case BehaviorTemplates::BEHAVIOR_CAMERA: break; case BehaviorTemplates::BEHAVIOR_REMOVE_BUFF: break; case BehaviorTemplates::BEHAVIOR_GRAB: break; case BehaviorTemplates::BEHAVIOR_MODULAR_BUILD: break; case BehaviorTemplates::BEHAVIOR_NPC_COMBAT_SKILL: behavior = new NpcCombatSkillBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_BLOCK: behavior = new BlockBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_VERIFY: behavior = new VerifyBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_TAUNT: behavior = new TauntBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_AIR_MOVEMENT: behavior = new AirMovementBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_SPAWN_QUICKBUILD: behavior = new SpawnBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_PULL_TO_POINT: behavior = new PullToPointBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_PROPERTY_ROTATE: break; case BehaviorTemplates::BEHAVIOR_DAMAGE_REDUCTION: behavior = new DamageReductionBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_PROPERTY_TELEPORT: break; case BehaviorTemplates::BEHAVIOR_PROPERTY_CLEAR_TARGET: behavior = new ClearTargetBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_TAKE_PICTURE: break; case BehaviorTemplates::BEHAVIOR_MOUNT: break; case BehaviorTemplates::BEHAVIOR_SKILL_SET: break; default: //Game::logger->Log("Behavior", "Failed to load behavior with invalid template id (%i)!\n", templateId); break; } if (behavior == nullptr) { //Game::logger->Log("Behavior", "Failed to load unimplemented template id (%i)!\n", templateId); behavior = new EmptyBehavior(behaviorId); } behavior->Load(); return behavior; } BehaviorTemplates Behavior::GetBehaviorTemplate(const uint32_t behaviorId) { std::stringstream query; query << "SELECT templateID FROM BehaviorTemplate WHERE behaviorID = " << std::to_string(behaviorId); auto result = CDClientDatabase::ExecuteQuery(query.str()); // Make sure we do not proceed if we are trying to load an invalid behavior if (result.eof()) { if (behaviorId != 0) { Game::logger->Log("Behavior::GetBehaviorTemplate", "Failed to load behavior template with id (%i)!\n", behaviorId); } return BehaviorTemplates::BEHAVIOR_EMPTY; } const auto id = static_cast(result.getIntField(0)); result.finalize(); return id; } // For use with enemies, to display the correct damage animations on the players void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID secondary) { auto* targetEntity = EntityManager::Instance()->GetEntity(target); if (targetEntity == nullptr) { return; } const auto effectId = this->m_effectId; if (effectId == 0) { GameMessages::SendPlayFXEffect(targetEntity, -1, type, "", secondary, 1, 1, true); return; } auto* renderComponent = targetEntity->GetComponent(); const auto typeString = GeneralUtils::UTF16ToWTF8(type); if (m_effectNames == nullptr) { m_effectNames = new std::unordered_map(); } else { const auto pair = m_effectNames->find(typeString); if (type.empty()) { type = GeneralUtils::ASCIIToUTF16(*m_effectType); } if (pair != m_effectNames->end()) { if (renderComponent == nullptr) { GameMessages::SendPlayFXEffect(targetEntity, effectId, type, pair->second, secondary, 1, 1, true); return; } renderComponent->PlayEffect(effectId, type, pair->second, secondary); return; } } std::stringstream query; if (!type.empty()) { query << "SELECT effectName FROM BehaviorEffect WHERE effectType = '" << typeString << "' AND effectID = " << std::to_string(effectId) << ";"; } else { query << "SELECT effectName, effectType FROM BehaviorEffect WHERE effectID = " << std::to_string(effectId) << ";"; } auto result = CDClientDatabase::ExecuteQuery(query.str()); if (result.eof() || result.fieldIsNull(0)) { return; } const auto name = std::string(result.getStringField(0)); if (type.empty()) { const auto typeResult = result.getStringField(1); type = GeneralUtils::ASCIIToUTF16(typeResult); m_effectType = new std::string(typeResult); } result.finalize(); m_effectNames->insert_or_assign(typeString, name); if (renderComponent == nullptr) { GameMessages::SendPlayFXEffect(targetEntity, effectId, type, name, secondary, 1, 1, true); return; } renderComponent->PlayEffect(effectId, type, name, secondary); } Behavior::Behavior(const uint32_t behaviorId) { this->m_behaviorId = behaviorId; // Add to cache Cache.insert_or_assign(behaviorId, this); if (behaviorId == 0) { this->m_effectId = 0; this->m_effectHandle = nullptr; this->m_templateId = BehaviorTemplates::BEHAVIOR_EMPTY; } /* * Get standard info */ std::stringstream query; query << "SELECT templateID, effectID, effectHandle FROM BehaviorTemplate WHERE behaviorID = " << std::to_string(behaviorId); auto result = CDClientDatabase::ExecuteQuery(query.str()); // Make sure we do not proceed if we are trying to load an invalid behavior if (result.eof()) { Game::logger->Log("Behavior", "Failed to load behavior with id (%i)!\n", behaviorId); this->m_effectId = 0; this->m_effectHandle = nullptr; this->m_templateId = BehaviorTemplates::BEHAVIOR_EMPTY; return; } this->m_templateId = static_cast(result.getIntField(0)); this->m_effectId = result.getIntField(1); if (!result.fieldIsNull(2)) { const std::string effectHandle = result.getStringField(2); if (effectHandle == "") { this->m_effectHandle = nullptr; } else { this->m_effectHandle = new std::string(effectHandle); } } else { this->m_effectHandle = nullptr; } result.finalize(); } float Behavior::GetFloat(const std::string& name, const float defaultValue) const { return BehaviorParameterTable->GetEntry(this->m_behaviorId, name, defaultValue); } bool Behavior::GetBoolean(const std::string& name, const bool defaultValue) const { return GetFloat(name, defaultValue) > 0; } int32_t Behavior::GetInt(const std::string& name, const int defaultValue) const { return static_cast(GetFloat(name, defaultValue)); } Behavior* Behavior::GetAction(const std::string& name) const { const auto id = GetInt(name); return CreateBehavior(id); } Behavior* Behavior::GetAction(float value) const { return CreateBehavior(static_cast(value)); } std::map Behavior::GetParameterNames() const { std::map parameters; std::stringstream query; query << "SELECT parameterID, value FROM BehaviorParameter WHERE behaviorID = " << std::to_string(this->m_behaviorId); auto tableData = CDClientDatabase::ExecuteQuery(query.str()); while (!tableData.eof()) { parameters.insert_or_assign(tableData.getStringField(0, ""), tableData.getFloatField(1, 0)); tableData.nextRow(); } tableData.finalize(); return parameters; } void Behavior::Load() { } void Behavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { } void Behavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { } void Behavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { } void Behavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { } 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) { } Behavior::~Behavior() { delete m_effectNames; delete m_effectType; delete m_effectHandle; }