Merge branch 'main' into npc-pathing

This commit is contained in:
Aaron Kimbre
2023-04-10 22:19:41 -05:00
612 changed files with 12044 additions and 7169 deletions

View File

@@ -0,0 +1,45 @@
#include "eMissionTaskType.h"
#ifndef __ACHIEVEMENTCACHEKEY__H__
#define __ACHIEVEMENTCACHEKEY__H__
class AchievementCacheKey {
public:
AchievementCacheKey() {
targets = "";
value = 0;
type = eMissionTaskType::UNKNOWN;
};
bool operator==(const AchievementCacheKey& point) const {
return this->targets == point.targets && this->value == point.value && this->type == point.type;
};
void SetTargets(const std::string value) { this->targets = value; };
void SetValue(uint32_t value) { this->value = value; };
void SetType(eMissionTaskType value) { this->type = value; };
std::string GetTargets() const { return this->targets; };
uint32_t GetValue() const { return this->value; };
eMissionTaskType GetType() const { return this->type; };
private:
std::string targets;
uint32_t value;
eMissionTaskType type;
};
// Specialization of hash for the above class
namespace std {
template<>
struct hash<AchievementCacheKey> {
size_t operator()(const AchievementCacheKey& key) const {
size_t hash = 0;
GeneralUtils::hash_combine(hash, key.GetType());
GeneralUtils::hash_combine(hash, key.GetValue());
GeneralUtils::hash_combine(hash, key.GetTargets());
return hash;
};
};
};
#endif //!__ACHIEVEMENTCACHEKEY__H__

View File

@@ -22,10 +22,13 @@
#include "SkillComponent.h"
#include "RebuildComponent.h"
#include "DestroyableComponent.h"
#include "Metrics.hpp"
#include "CDComponentsRegistryTable.h"
#include "CDPhysicsComponentTable.h"
BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id) : Component(parent) {
BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id): Component(parent) {
m_Target = LWOOBJID_EMPTY;
m_State = AiState::spawn;
SetAiState(AiState::spawn);
m_Timer = 1.0f;
m_StartPosition = parent->GetPosition();
m_MovementAI = nullptr;
@@ -104,10 +107,10 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id)
int32_t collisionGroup = (COLLISION_GROUP_DYNAMIC | COLLISION_GROUP_ENEMY);
CDComponentsRegistryTable* componentRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
auto componentID = componentRegistryTable->GetByIDAndType(parent->GetLOT(), COMPONENT_TYPE_CONTROLLABLE_PHYSICS);
CDComponentsRegistryTable* componentRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
auto componentID = componentRegistryTable->GetByIDAndType(parent->GetLOT(), eReplicaComponentType::CONTROLLABLE_PHYSICS);
CDPhysicsComponentTable* physicsComponentTable = CDClientManager::Instance()->GetTable<CDPhysicsComponentTable>("PhysicsComponent");
CDPhysicsComponentTable* physicsComponentTable = CDClientManager::Instance().GetTable<CDPhysicsComponentTable>();
if (physicsComponentTable != nullptr) {
auto* info = physicsComponentTable->GetByID(componentID);
@@ -179,7 +182,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) {
if (m_Disabled || m_Parent->GetIsDead())
return;
bool stunnedThisFrame = m_Stunned;
CalculateCombat(deltaTime); // Putting this here for now
if (m_StartPosition == NiPoint3::ZERO) {
@@ -192,7 +195,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) {
return;
}
if (m_Stunned) {
if (stunnedThisFrame) {
m_MovementAI->Stop();
return;
@@ -206,7 +209,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) {
switch (m_State) {
case AiState::spawn:
Stun(2.0f);
m_State = AiState::idle;
SetAiState(AiState::idle);
break;
case AiState::idle:
@@ -228,6 +231,18 @@ void BaseCombatAIComponent::Update(const float deltaTime) {
void BaseCombatAIComponent::CalculateCombat(const float deltaTime) {
bool hasSkillToCast = false;
for (auto& entry : m_SkillEntries) {
if (entry.cooldown > 0.0f) {
entry.cooldown -= deltaTime;
} else {
hasSkillToCast = true;
}
}
bool hadRemainingDowntime = m_SkillTime > 0.0f;
if (m_SkillTime > 0.0f) m_SkillTime -= deltaTime;
auto* rebuild = m_Parent->GetComponent<RebuildComponent>();
if (rebuild != nullptr) {
@@ -248,19 +263,17 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) {
if (m_Disabled) return;
if (m_StunTime > 0.0f) {
if (m_Stunned) {
m_StunTime -= deltaTime;
if (m_StunTime > 0.0f) {
return;
}
m_StunTime = 0.0f;
m_Stunned = false;
}
if (m_Stunned) {
return;
}
if (m_Stunned || hadRemainingDowntime) return;
auto newTarget = FindTarget();
@@ -320,41 +333,19 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) {
m_Timer = 0;
}
m_State = AiState::aggro;
SetAiState(AiState::aggro);
} else {
m_State = AiState::idle;
SetAiState(AiState::idle);
}
for (auto i = 0; i < m_SkillEntries.size(); ++i) {
auto entry = m_SkillEntries.at(i);
if (entry.cooldown > 0) {
entry.cooldown -= deltaTime;
m_SkillEntries[i] = entry;
}
}
if (m_SkillTime > 0) {
m_SkillTime -= deltaTime;
return;
}
if (m_Downtime > 0) {
m_Downtime -= deltaTime;
return;
}
if (!hasSkillToCast) return;
if (m_Target == LWOOBJID_EMPTY) {
m_State = AiState::idle;
SetAiState(AiState::idle);
return;
}
m_Downtime = 0.5f;
auto* target = GetTargetEntity();
if (target != nullptr) {
@@ -375,7 +366,7 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) {
m_MovementAI->Stop();
}
m_State = AiState::aggro;
SetAiState(AiState::aggro);
m_Timer = 0;
@@ -532,11 +523,20 @@ bool BaseCombatAIComponent::IsMech() {
void BaseCombatAIComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
outBitStream->Write1();
outBitStream->Write(uint32_t(m_State));
outBitStream->Write(m_Target);
outBitStream->Write(m_DirtyStateOrTarget || bIsInitialUpdate);
if (m_DirtyStateOrTarget || bIsInitialUpdate) {
outBitStream->Write(uint32_t(m_State));
outBitStream->Write(m_Target);
m_DirtyStateOrTarget = false;
}
}
void BaseCombatAIComponent::SetAiState(AiState newState) {
if (newState == this->m_State) return;
this->m_State = newState;
m_DirtyStateOrTarget = true;
EntityManager::Instance()->SerializeEntity(m_Parent);
}
bool BaseCombatAIComponent::IsEnemy(LWOOBJID target) const {
auto* entity = EntityManager::Instance()->GetEntity(target);
@@ -585,7 +585,10 @@ bool BaseCombatAIComponent::IsEnemy(LWOOBJID target) const {
}
void BaseCombatAIComponent::SetTarget(const LWOOBJID target) {
if (this->m_Target == target) return;
m_Target = target;
m_DirtyStateOrTarget = true;
EntityManager::Instance()->SerializeEntity(m_Parent);
}
Entity* BaseCombatAIComponent::GetTargetEntity() const {
@@ -700,7 +703,7 @@ void BaseCombatAIComponent::OnAggro() {
m_MovementAI->SetDestination(targetPos);
m_State = AiState::tether;
SetAiState(AiState::tether);
}
m_Timer += 0.5f;
@@ -726,7 +729,7 @@ void BaseCombatAIComponent::OnTether() {
m_MovementAI->SetDestination(m_StartPosition);
m_State = AiState::aggro;
SetAiState(AiState::aggro);
} else {
if (IsMech() && Vector3::DistanceSquared(targetPos, currentPos) > m_AttackRadius * m_AttackRadius * 3 * 3) return;

View File

@@ -8,6 +8,7 @@
#include "dpWorld.h"
#include "dpEntity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
#include <vector>
#include <map>
@@ -46,7 +47,7 @@ struct AiSkillEntry
*/
class BaseCombatAIComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_BASE_COMBAT_AI;
static const eReplicaComponentType ComponentType = eReplicaComponentType::BASE_COMBAT_AI;
BaseCombatAIComponent(Entity* parentEntity, uint32_t id);
~BaseCombatAIComponent() override;
@@ -243,6 +244,12 @@ private:
*/
std::vector<LWOOBJID> GetTargetWithinAggroRange() const;
/**
* @brief Sets the AiState and prepares the entity for serialization next frame.
*
*/
void SetAiState(AiState newState);
/**
* The current state of the AI
*/
@@ -334,11 +341,6 @@ private:
*/
bool m_StunImmune = false;
/**
* Time taken between actions
*/
float m_Downtime = 0;
/**
* How long this entity needs to execute its skill
*/
@@ -374,6 +376,12 @@ private:
*/
bool m_DirtyThreat = false;
/**
* Whether or not the Component has dirty information and should update next frame
*
*/
bool m_DirtyStateOrTarget = false;
/**
* Whether the current entity is a mech enemy, needed as mechs tether radius works differently
* @return whether this entity is a mech

View File

@@ -7,6 +7,7 @@
#include "dLogger.h"
#include "GameMessages.h"
#include <BitStream.h>
#include "eTriggerEventType.h"
BouncerComponent::BouncerComponent(Entity* parent) : Component(parent) {
m_PetEnabled = false;
@@ -46,8 +47,10 @@ void BouncerComponent::SetPetBouncerEnabled(bool value) {
EntityManager::Instance()->SerializeEntity(m_Parent);
if (value) {
m_Parent->TriggerEvent(eTriggerEventType::PET_ON_SWITCH, m_Parent);
GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), 1513, u"create", "PetOnSwitch", LWOOBJID_EMPTY, 1, 1, true);
} else {
m_Parent->TriggerEvent(eTriggerEventType::PET_OFF_SWITCH, m_Parent);
GameMessages::SendStopFXEffect(m_Parent, true, "PetOnSwitch");
}

View File

@@ -5,13 +5,14 @@
#include "RakNetTypes.h"
#include "Entity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* Attached to bouncer entities, allowing other entities to bounce off of it
*/
class BouncerComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_BOUNCER;
static const eReplicaComponentType ComponentType = eReplicaComponentType::BOUNCER;
BouncerComponent(Entity* parentEntity);
~BouncerComponent() override;

View File

@@ -9,6 +9,8 @@
#include "SkillComponent.h"
#include "ControllablePhysicsComponent.h"
#include "EntityManager.h"
#include "CDClientManager.h"
#include "CDSkillBehaviorTable.h"
std::unordered_map<int32_t, std::vector<BuffParameter>> BuffComponent::m_Cache{};
@@ -100,7 +102,7 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO
const auto& parameters = GetBuffParameters(id);
for (const auto& parameter : parameters) {
if (parameter.name == "overtime") {
auto* behaviorTemplateTable = CDClientManager::Instance()->GetTable<CDSkillBehaviorTable>("SkillBehavior");
auto* behaviorTemplateTable = CDClientManager::Instance().GetTable<CDSkillBehaviorTable>();
behaviorID = behaviorTemplateTable->GetSkillByID(parameter.values[0]).behaviorID;
stacks = static_cast<int32_t>(parameter.values[1]);
@@ -123,13 +125,15 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO
m_Buffs.emplace(id, buff);
}
void BuffComponent::RemoveBuff(int32_t id) {
void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity) {
const auto& iter = m_Buffs.find(id);
if (iter == m_Buffs.end()) {
return;
}
GameMessages::SendRemoveBuff(m_Parent, fromUnEquip, removeImmunity, id);
m_Buffs.erase(iter);
RemoveBuffEffect(id);
@@ -167,17 +171,10 @@ void BuffComponent::ApplyBuffEffect(int32_t id) {
destroyable->SetMaxImagination(destroyable->GetMaxImagination() + maxImagination);
} else if (parameter.name == "speed") {
const auto speed = parameter.value;
auto* controllablePhysicsComponent = this->GetParent()->GetComponent<ControllablePhysicsComponent>();
if (controllablePhysicsComponent == nullptr) return;
const auto current = controllablePhysicsComponent->GetSpeedMultiplier();
controllablePhysicsComponent->SetSpeedMultiplier(current + ((speed - 500.0f) / 500.0f));
EntityManager::Instance()->SerializeEntity(this->GetParent());
if (!controllablePhysicsComponent) return;
const auto speed = parameter.value;
controllablePhysicsComponent->AddSpeedboost(speed);
}
}
}
@@ -210,17 +207,10 @@ void BuffComponent::RemoveBuffEffect(int32_t id) {
destroyable->SetMaxImagination(destroyable->GetMaxImagination() - maxImagination);
} else if (parameter.name == "speed") {
const auto speed = parameter.value;
auto* controllablePhysicsComponent = this->GetParent()->GetComponent<ControllablePhysicsComponent>();
if (controllablePhysicsComponent == nullptr) return;
const auto current = controllablePhysicsComponent->GetSpeedMultiplier();
controllablePhysicsComponent->SetSpeedMultiplier(current - ((speed - 500.0f) / 500.0f));
EntityManager::Instance()->SerializeEntity(this->GetParent());
if (!controllablePhysicsComponent) return;
const auto speed = parameter.value;
controllablePhysicsComponent->RemoveSpeedboost(speed);
}
}
}

View File

@@ -7,6 +7,7 @@
#include <unordered_map>
#include <map>
#include "Component.h"
#include "eReplicaComponentType.h"
class Entity;
@@ -41,7 +42,7 @@ struct Buff
*/
class BuffComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_BUFF;
static const eReplicaComponentType ComponentType = eReplicaComponentType::BUFF;
explicit BuffComponent(Entity* parent);
@@ -78,8 +79,9 @@ public:
/**
* Removes a buff from the parent entity, reversing its effects
* @param id the id of the buff to remove
* @param removeImmunity whether or not to remove immunity on removing the buff
*/
void RemoveBuff(int32_t id);
void RemoveBuff(int32_t id, bool fromUnEquip = false, bool removeImmunity = false);
/**
* Returns whether or not the entity has a buff identified by `id`

View File

@@ -9,13 +9,14 @@
#include "BitStream.h"
#include "Entity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* Component for the build border, allowing the user to start building when interacting with it
*/
class BuildBorderComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_BUILD_BORDER;
static const eReplicaComponentType ComponentType = eReplicaComponentType::BUILD_BORDER;
BuildBorderComponent(Entity* parent);
~BuildBorderComponent() override;

View File

@@ -38,5 +38,6 @@ set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp"
"SkillComponent.cpp"
"SoundTriggerComponent.cpp"
"SwitchComponent.cpp"
"TriggerComponent.cpp"
"VehiclePhysicsComponent.cpp"
"VendorComponent.cpp" PARENT_SCOPE)

View File

@@ -13,6 +13,8 @@
#include "VehiclePhysicsComponent.h"
#include "GameMessages.h"
#include "Item.h"
#include "AMFFormat.h"
#include "eGameMasterLevel.h"
CharacterComponent::CharacterComponent(Entity* parent, Character* character) : Component(parent) {
m_Character = character;
@@ -42,7 +44,6 @@ bool CharacterComponent::LandingAnimDisabled(int zoneID) {
switch (zoneID) {
case 0:
case 556:
case 1001:
case 1101:
case 1202:
case 1203:
@@ -165,9 +166,9 @@ void CharacterComponent::SetPvpEnabled(const bool value) {
m_PvpEnabled = value;
}
void CharacterComponent::SetGMLevel(int gmlevel) {
void CharacterComponent::SetGMLevel(eGameMasterLevel gmlevel) {
m_DirtyGMInfo = true;
if (gmlevel > 0) m_IsGM = true;
if (gmlevel > eGameMasterLevel::CIVILIAN) m_IsGM = true;
else m_IsGM = false;
m_GMLevel = gmlevel;
}
@@ -239,7 +240,7 @@ void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
// End custom attributes
//
if (m_GMLevel > 0) {
if (m_GMLevel > eGameMasterLevel::CIVILIAN) {
m_IsGM = true;
m_DirtyGMInfo = true;
m_EditorLevel = m_GMLevel;

View File

@@ -9,6 +9,7 @@
#include <string>
#include "CDMissionsTable.h"
#include "tinyxml2.h"
#include "eReplicaComponentType.h"
/**
* The statistics that can be achieved per zone
@@ -59,7 +60,7 @@ enum StatisticID {
*/
class CharacterComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_CHARACTER;
static const eReplicaComponentType ComponentType = eReplicaComponentType::CHARACTER;
CharacterComponent(Entity* parent, Character* character);
~CharacterComponent() override;
@@ -177,7 +178,7 @@ public:
* Sets the GM level of the character, should be called in the entity. Here it's set for serialization
* @param gmlevel the gm level to set
*/
void SetGMLevel(int gmlevel);
void SetGMLevel(eGameMasterLevel gmlevel);
/**
* Initializes the player statistics from the string stored in the XML
@@ -332,7 +333,7 @@ private:
/**
* The current GM level of this character (anything > 0 counts as a GM)
*/
unsigned char m_GMLevel;
eGameMasterLevel m_GMLevel;
/**
* Whether the character has HF enabled
@@ -342,7 +343,7 @@ private:
/**
* The level of the character in HF
*/
unsigned char m_EditorLevel;
eGameMasterLevel m_EditorLevel;
/**
* Whether the currently active activity has been changed

View File

@@ -12,6 +12,7 @@
#include "EntityManager.h"
#include "Character.h"
#include "dZoneManager.h"
#include "LevelProgressionComponent.h"
ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Component(entity) {
m_Position = {};
@@ -30,10 +31,25 @@ ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Com
m_GravityScale = 1;
m_DirtyCheats = false;
m_IgnoreMultipliers = false;
m_DirtyEquippedItemInfo = true;
m_PickupRadius = 0.0f;
m_DirtyPickupRadiusScale = true;
m_DirtyBubble = false;
m_IsInBubble = false;
m_SpecialAnims = false;
m_BubbleType = eBubbleType::DEFAULT;
m_IsTeleporting = false;
m_ImmuneToStunAttackCount = 0;
m_ImmuneToStunEquipCount = 0;
m_ImmuneToStunInteractCount = 0;
m_ImmuneToStunJumpCount = 0;
m_ImmuneToStunMoveCount = 0;
m_ImmuneToStunTurnCount = 0;
m_ImmuneToStunUseItemCount = 0;
if (entity->GetLOT() != 1) // Other physics entities we care about will be added by BaseCombatAI
return;
@@ -70,16 +86,17 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo
outBitStream->Write(m_JetpackBypassChecks);
}
outBitStream->Write0(); //This contains info about immunities, but for now I'm leaving it out.
outBitStream->Write1(); // always write these on construction
outBitStream->Write(m_ImmuneToStunMoveCount);
outBitStream->Write(m_ImmuneToStunJumpCount);
outBitStream->Write(m_ImmuneToStunTurnCount);
outBitStream->Write(m_ImmuneToStunAttackCount);
outBitStream->Write(m_ImmuneToStunUseItemCount);
outBitStream->Write(m_ImmuneToStunEquipCount);
outBitStream->Write(m_ImmuneToStunInteractCount);
}
if (m_SpeedMultiplier < 1.0f) {
m_DirtyCheats = false;
}
if (m_IgnoreMultipliers) {
m_DirtyCheats = false;
}
if (m_IgnoreMultipliers) m_DirtyCheats = false;
outBitStream->Write(m_DirtyCheats);
if (m_DirtyCheats) {
@@ -89,14 +106,22 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo
m_DirtyCheats = false;
}
outBitStream->Write(m_DirtyPickupRadiusScale);
if (m_DirtyPickupRadiusScale) {
outBitStream->Write(m_DirtyEquippedItemInfo);
if (m_DirtyEquippedItemInfo) {
outBitStream->Write(m_PickupRadius);
outBitStream->Write0(); //No clue what this is so im leaving it false.
m_DirtyPickupRadiusScale = false;
outBitStream->Write(m_InJetpackMode);
m_DirtyEquippedItemInfo = false;
}
outBitStream->Write0();
outBitStream->Write(m_DirtyBubble);
if (m_DirtyBubble) {
outBitStream->Write(m_IsInBubble);
if (m_IsInBubble) {
outBitStream->Write(m_BubbleType);
outBitStream->Write(m_SpecialAnims);
}
m_DirtyBubble = false;
}
outBitStream->Write(m_DirtyPosition || bIsInitialUpdate);
if (m_DirtyPosition || bIsInitialUpdate) {
@@ -253,7 +278,7 @@ void ControllablePhysicsComponent::AddPickupRadiusScale(float value) {
m_ActivePickupRadiusScales.push_back(value);
if (value > m_PickupRadius) {
m_PickupRadius = value;
m_DirtyPickupRadiusScale = true;
m_DirtyEquippedItemInfo = true;
}
}
@@ -263,16 +288,102 @@ void ControllablePhysicsComponent::RemovePickupRadiusScale(float value) {
if (pos != m_ActivePickupRadiusScales.end()) {
m_ActivePickupRadiusScales.erase(pos);
} else {
Game::logger->Log("ControllablePhysicsComponent", "Warning: Could not find pickup radius %f in list of active radii. List has %i active radii.", value, m_ActivePickupRadiusScales.size());
Game::logger->LogDebug("ControllablePhysicsComponent", "Warning: Could not find pickup radius %f in list of active radii. List has %i active radii.", value, m_ActivePickupRadiusScales.size());
return;
}
// Recalculate pickup radius since we removed one by now
m_PickupRadius = 0.0f;
m_DirtyPickupRadiusScale = true;
m_DirtyEquippedItemInfo = true;
for (uint32_t i = 0; i < m_ActivePickupRadiusScales.size(); i++) {
auto candidateRadius = m_ActivePickupRadiusScales[i];
if (m_PickupRadius < candidateRadius) m_PickupRadius = candidateRadius;
}
EntityManager::Instance()->SerializeEntity(m_Parent);
}
void ControllablePhysicsComponent::AddSpeedboost(float value) {
m_ActiveSpeedBoosts.push_back(value);
m_SpeedBoost = value;
SetSpeedMultiplier(value / 500.0f); // 500 being the base speed
}
void ControllablePhysicsComponent::RemoveSpeedboost(float value) {
const auto pos = std::find(m_ActiveSpeedBoosts.begin(), m_ActiveSpeedBoosts.end(), value);
if (pos != m_ActiveSpeedBoosts.end()) {
m_ActiveSpeedBoosts.erase(pos);
} else {
Game::logger->LogDebug("ControllablePhysicsComponent", "Warning: Could not find speedboost %f in list of active speedboosts. List has %i active speedboosts.", value, m_ActiveSpeedBoosts.size());
return;
}
// Recalculate speedboost since we removed one
m_SpeedBoost = 0.0f;
if (m_ActiveSpeedBoosts.size() == 0) { // no active speed boosts left, so return to base speed
auto* levelProgressionComponent = m_Parent->GetComponent<LevelProgressionComponent>();
if (levelProgressionComponent) m_SpeedBoost = levelProgressionComponent->GetSpeedBase();
} else { // Used the last applied speedboost
m_SpeedBoost = m_ActiveSpeedBoosts.back();
}
SetSpeedMultiplier(m_SpeedBoost / 500.0f); // 500 being the base speed
EntityManager::Instance()->SerializeEntity(m_Parent);
}
void ControllablePhysicsComponent::ActivateBubbleBuff(eBubbleType bubbleType, bool specialAnims){
if (m_IsInBubble) {
Game::logger->Log("ControllablePhysicsComponent", "Already in bubble");
return;
}
m_BubbleType = bubbleType;
m_IsInBubble = true;
m_DirtyBubble = true;
m_SpecialAnims = specialAnims;
EntityManager::Instance()->SerializeEntity(m_Parent);
}
void ControllablePhysicsComponent::DeactivateBubbleBuff(){
m_DirtyBubble = true;
m_IsInBubble = false;
EntityManager::Instance()->SerializeEntity(m_Parent);
};
void ControllablePhysicsComponent::SetStunImmunity(
const eStateChangeType state,
const LWOOBJID originator,
const bool bImmuneToStunAttack,
const bool bImmuneToStunEquip,
const bool bImmuneToStunInteract,
const bool bImmuneToStunJump,
const bool bImmuneToStunMove,
const bool bImmuneToStunTurn,
const bool bImmuneToStunUseItem){
if (state == eStateChangeType::POP){
if (bImmuneToStunAttack && m_ImmuneToStunAttackCount > 0) m_ImmuneToStunAttackCount -= 1;
if (bImmuneToStunEquip && m_ImmuneToStunEquipCount > 0) m_ImmuneToStunEquipCount -= 1;
if (bImmuneToStunInteract && m_ImmuneToStunInteractCount > 0) m_ImmuneToStunInteractCount -= 1;
if (bImmuneToStunJump && m_ImmuneToStunJumpCount > 0) m_ImmuneToStunJumpCount -= 1;
if (bImmuneToStunMove && m_ImmuneToStunMoveCount > 0) m_ImmuneToStunMoveCount -= 1;
if (bImmuneToStunTurn && m_ImmuneToStunTurnCount > 0) m_ImmuneToStunTurnCount -= 1;
if (bImmuneToStunUseItem && m_ImmuneToStunUseItemCount > 0) m_ImmuneToStunUseItemCount -= 1;
} else if (state == eStateChangeType::PUSH) {
if (bImmuneToStunAttack) m_ImmuneToStunAttackCount += 1;
if (bImmuneToStunEquip) m_ImmuneToStunEquipCount += 1;
if (bImmuneToStunInteract) m_ImmuneToStunInteractCount += 1;
if (bImmuneToStunJump) m_ImmuneToStunJumpCount += 1;
if (bImmuneToStunMove) m_ImmuneToStunMoveCount += 1;
if (bImmuneToStunTurn) m_ImmuneToStunTurnCount += 1;
if (bImmuneToStunUseItem) m_ImmuneToStunUseItemCount += 1;
}
GameMessages::SendSetStunImmunity(
m_Parent->GetObjectID(), state, m_Parent->GetSystemAddress(), originator,
bImmuneToStunAttack,
bImmuneToStunEquip,
bImmuneToStunInteract,
bImmuneToStunJump,
bImmuneToStunMove,
bImmuneToStunTurn,
bImmuneToStunUseItem
);
}

View File

@@ -9,6 +9,8 @@
#include "Component.h"
#include "dpCollisionChecks.h"
#include "PhantomPhysicsComponent.h"
#include "eBubbleType.h"
#include "eReplicaComponentType.h"
class Entity;
class dpEntity;
@@ -18,7 +20,7 @@ class dpEntity;
*/
class ControllablePhysicsComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_CONTROLLABLE_PHYSICS;
static const eReplicaComponentType ComponentType = eReplicaComponentType::CONTROLLABLE_PHYSICS;
ControllablePhysicsComponent(Entity* entity);
~ControllablePhysicsComponent() override;
@@ -257,6 +259,63 @@ public:
*/
std::vector<float> GetActivePickupRadiusScales() { return m_ActivePickupRadiusScales; };
/**
* Add a Speed boost to the entity
* This will recalculate the speed boost based on what is being added
*/
void AddSpeedboost(float value);
/**
* Remove speed boost from entity
* This will recalculate the speed boost based on what is the last one in te vector
*/
void RemoveSpeedboost(float value);
/**
* The speed boosts of this component.
* @return All active Speed boosts for this component.
*/
std::vector<float> GetActiveSpeedboosts() { return m_ActivePickupRadiusScales; };
/**
* Activates the Bubble Buff
*/
void ActivateBubbleBuff(eBubbleType bubbleType = eBubbleType::DEFAULT, bool specialAnims = true);
/**
* Deactivates the Bubble Buff
*/
void DeactivateBubbleBuff();
/**
* Gets if the Entity is in a bubble
*/
bool GetIsInBubble(){ return m_IsInBubble; };
/**
* Push or Pop a layer of stun immunity to this entity
*/
void SetStunImmunity(
const eStateChangeType state,
const LWOOBJID originator = LWOOBJID_EMPTY,
const bool bImmuneToStunAttack = false,
const bool bImmuneToStunEquip = false,
const bool bImmuneToStunInteract = false,
const bool bImmuneToStunJump = false,
const bool bImmuneToStunMove = false,
const bool bImmuneToStunTurn = false,
const bool bImmuneToStunUseItem = false
);
// getters for stun immunities
const bool GetImmuneToStunAttack() { return m_ImmuneToStunAttackCount > 0;};
const bool GetImmuneToStunEquip() { return m_ImmuneToStunEquipCount > 0;};
const bool GetImmuneToStunInteract() { return m_ImmuneToStunInteractCount > 0;};
const bool GetImmuneToStunJump() { return m_ImmuneToStunJumpCount > 0;};
const bool GetImmuneToStunMove() { return m_ImmuneToStunMoveCount > 0;};
const bool GetImmuneToStunTurn() { return m_ImmuneToStunTurnCount > 0;};
const bool GetImmuneToStunUseItem() { return m_ImmuneToStunUseItemCount > 0;};
private:
/**
* The entity that owns this component
@@ -356,7 +415,7 @@ private:
/**
* Whether the pickup scale is dirty.
*/
bool m_DirtyPickupRadiusScale;
bool m_DirtyEquippedItemInfo;
/**
* The list of pickup radius scales for this entity
@@ -372,6 +431,47 @@ private:
* If the entity is teleporting
*/
bool m_IsTeleporting;
/**
* The list of speed boosts for this entity
*/
std::vector<float> m_ActiveSpeedBoosts;
/**
* The active speed boost for this entity
*/
float m_SpeedBoost;
/*
* If Bubble info is dirty
*/
bool m_DirtyBubble;
/*
* If the entity is in a bubble
*/
bool m_IsInBubble;
/*
* The type of bubble the entity has
*/
eBubbleType m_BubbleType;
/*
* If the entity should be using the special animations
*/
bool m_SpecialAnims;
/**
* stun immunity counters
*/
int32_t m_ImmuneToStunAttackCount;
int32_t m_ImmuneToStunEquipCount;
int32_t m_ImmuneToStunInteractCount;
int32_t m_ImmuneToStunJumpCount;
int32_t m_ImmuneToStunMoveCount;
int32_t m_ImmuneToStunTurnCount;
int32_t m_ImmuneToStunUseItemCount;
};
#endif // CONTROLLABLEPHYSICSCOMPONENT_H

View File

@@ -2,6 +2,7 @@
#include <BitStream.h>
#include "dLogger.h"
#include "Game.h"
#include "dConfig.h"
#include "AMFFormat.h"
#include "AMFFormat_BitStream.h"
@@ -28,7 +29,12 @@
#include "CharacterComponent.h"
#include "PossessableComponent.h"
#include "PossessorComponent.h"
#include "InventoryComponent.h"
#include "dZoneManager.h"
#include "WorldConfig.h"
#include "eMissionTaskType.h"
#include "CDComponentsRegistryTable.h"
DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) {
m_iArmor = 0;
@@ -53,26 +59,35 @@ DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) {
m_LootMatrixID = 0;
m_MinCoins = 0;
m_MaxCoins = 0;
m_ImmuneStacks = 0;
m_DamageReduction = 0;
m_ImmuneToBasicAttackCount = 0;
m_ImmuneToDamageOverTimeCount = 0;
m_ImmuneToKnockbackCount = 0;
m_ImmuneToInterruptCount = 0;
m_ImmuneToSpeedCount = 0;
m_ImmuneToImaginationGainCount = 0;
m_ImmuneToImaginationLossCount = 0;
m_ImmuneToQuickbuildInterruptCount = 0;
m_ImmuneToPullToPointCount = 0;
}
DestroyableComponent::~DestroyableComponent() {
}
void DestroyableComponent::Reinitialize(LOT templateID) {
CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
int32_t buffComponentID = compRegistryTable->GetByIDAndType(templateID, COMPONENT_TYPE_BUFF);
int32_t collectibleComponentID = compRegistryTable->GetByIDAndType(templateID, COMPONENT_TYPE_COLLECTIBLE);
int32_t rebuildComponentID = compRegistryTable->GetByIDAndType(templateID, COMPONENT_TYPE_REBUILD);
int32_t buffComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::BUFF);
int32_t collectibleComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::COLLECTIBLE);
int32_t rebuildComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::QUICK_BUILD);
int32_t componentID = 0;
if (collectibleComponentID > 0) componentID = collectibleComponentID;
if (rebuildComponentID > 0) componentID = rebuildComponentID;
if (buffComponentID > 0) componentID = buffComponentID;
CDDestructibleComponentTable* destCompTable = CDClientManager::Instance()->GetTable<CDDestructibleComponentTable>("DestructibleComponent");
CDDestructibleComponentTable* destCompTable = CDClientManager::Instance().GetTable<CDDestructibleComponentTable>();
std::vector<CDDestructibleComponent> destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); });
if (componentID > 0) {
@@ -104,7 +119,16 @@ void DestroyableComponent::Reinitialize(LOT templateID) {
void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags) {
if (bIsInitialUpdate) {
outBitStream->Write0(); //Contains info about immunities this object has, but it's left out for now.
outBitStream->Write1(); // always write these on construction
outBitStream->Write(m_ImmuneToBasicAttackCount);
outBitStream->Write(m_ImmuneToDamageOverTimeCount);
outBitStream->Write(m_ImmuneToKnockbackCount);
outBitStream->Write(m_ImmuneToInterruptCount);
outBitStream->Write(m_ImmuneToSpeedCount);
outBitStream->Write(m_ImmuneToImaginationGainCount);
outBitStream->Write(m_ImmuneToImaginationLossCount);
outBitStream->Write(m_ImmuneToQuickbuildInterruptCount);
outBitStream->Write(m_ImmuneToPullToPointCount);
}
outBitStream->Write(m_DirtyHealth || bIsInitialUpdate);
@@ -138,25 +162,17 @@ void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn
if (m_IsSmashable) {
outBitStream->Write(m_HasBricks);
if (m_ExplodeFactor != 1.0f) {
outBitStream->Write1();
outBitStream->Write(m_ExplodeFactor);
} else {
outBitStream->Write0();
}
outBitStream->Write(m_ExplodeFactor != 1.0f);
if (m_ExplodeFactor != 1.0f) outBitStream->Write(m_ExplodeFactor);
}
}
m_DirtyHealth = false;
}
outBitStream->Write(m_DirtyThreatList || bIsInitialUpdate);
if (m_DirtyThreatList || bIsInitialUpdate) {
outBitStream->Write1();
outBitStream->Write(m_HasThreats);
m_DirtyThreatList = false;
} else {
outBitStream->Write0();
}
}
@@ -342,7 +358,7 @@ void DestroyableComponent::SetDamageReduction(int32_t value) {
void DestroyableComponent::SetIsImmune(bool value) {
m_DirtyHealth = true;
m_ImmuneStacks = value ? 1 : 0;
m_ImmuneToBasicAttackCount = value ? 1 : 0;
}
void DestroyableComponent::SetIsGMImmune(bool value) {
@@ -438,7 +454,6 @@ void DestroyableComponent::AddEnemyFaction(int32_t factionID) {
void DestroyableComponent::SetIsSmashable(bool value) {
m_DirtyHealth = true;
m_IsSmashable = value;
//m_HasBricks = value;
}
void DestroyableComponent::SetAttacksToBlock(const uint32_t value) {
@@ -446,7 +461,7 @@ void DestroyableComponent::SetAttacksToBlock(const uint32_t value) {
}
bool DestroyableComponent::IsImmune() const {
return m_ImmuneStacks > 0 || m_IsGMImmune;
return m_IsGMImmune || m_ImmuneToBasicAttackCount > 0;
}
bool DestroyableComponent::IsKnockbackImmune() const {
@@ -455,9 +470,9 @@ bool DestroyableComponent::IsKnockbackImmune() const {
if (characterComponent != nullptr && inventoryComponent != nullptr && characterComponent->GetCurrentActivity() == eGameActivities::ACTIVITY_QUICKBUILDING) {
const auto hasPassive = inventoryComponent->HasAnyPassive({
ItemSetPassiveAbilityID::EngineerRank2, ItemSetPassiveAbilityID::EngineerRank3,
ItemSetPassiveAbilityID::SummonerRank2, ItemSetPassiveAbilityID::SummonerRank3,
ItemSetPassiveAbilityID::InventorRank2, ItemSetPassiveAbilityID::InventorRank3,
eItemSetPassiveAbilityID::EngineerRank2, eItemSetPassiveAbilityID::EngineerRank3,
eItemSetPassiveAbilityID::SummonerRank2, eItemSetPassiveAbilityID::SummonerRank3,
eItemSetPassiveAbilityID::InventorRank2, eItemSetPassiveAbilityID::InventorRank3,
}, 5);
if (hasPassive) {
@@ -639,6 +654,7 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
auto* attacker = EntityManager::Instance()->GetEntity(source);
m_Parent->OnHit(attacker);
m_Parent->OnHitOrHealResult(attacker, sourceDamage);
NotifySubscribers(attacker, sourceDamage);
for (const auto& cb : m_OnHitCallbacks) {
cb(attacker);
@@ -653,9 +669,38 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
return;
}
//check if hardcore mode is enabled
if (EntityManager::Instance()->GetHardcoreMode()) {
DoHardcoreModeDrops(source);
}
Smash(source, eKillType::VIOLENT, u"", skillID);
}
void DestroyableComponent::Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd) {
m_SubscribedScripts.insert(std::make_pair(scriptObjId, scriptToAdd));
Game::logger->LogDebug("DestroyableComponent", "Added script %llu to entity %llu", scriptObjId, m_Parent->GetObjectID());
Game::logger->LogDebug("DestroyableComponent", "Number of subscribed scripts %i", m_SubscribedScripts.size());
}
void DestroyableComponent::Unsubscribe(LWOOBJID scriptObjId) {
auto foundScript = m_SubscribedScripts.find(scriptObjId);
if (foundScript != m_SubscribedScripts.end()) {
m_SubscribedScripts.erase(foundScript);
Game::logger->LogDebug("DestroyableComponent", "Removed script %llu from entity %llu", scriptObjId, m_Parent->GetObjectID());
} else {
Game::logger->LogDebug("DestroyableComponent", "Tried to remove a script for Entity %llu but script %llu didnt exist", m_Parent->GetObjectID(), scriptObjId);
}
Game::logger->LogDebug("DestroyableComponent", "Number of subscribed scripts %i", m_SubscribedScripts.size());
}
void DestroyableComponent::NotifySubscribers(Entity* attacker, uint32_t damage) {
for (auto script : m_SubscribedScripts) {
script.second->NotifyHitOrHealResult(m_Parent, attacker, damage);
}
}
void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType, uint32_t skillID) {
if (m_iHealth > 0) {
SetArmor(0);
@@ -678,13 +723,13 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
auto* inventoryComponent = owner->GetComponent<InventoryComponent>();
if (inventoryComponent != nullptr && isEnemy) {
inventoryComponent->TriggerPassiveAbility(PassiveAbilityTrigger::EnemySmashed);
inventoryComponent->TriggerPassiveAbility(PassiveAbilityTrigger::EnemySmashed, m_Parent);
}
auto* missions = owner->GetComponent<MissionComponent>();
if (missions != nullptr) {
if (team != nullptr && isEnemy) {
if (team != nullptr) {
for (const auto memberId : team->members) {
auto* member = EntityManager::Instance()->GetEntity(memberId);
@@ -694,12 +739,12 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
if (memberMissions == nullptr) continue;
memberMissions->Progress(MissionTaskType::MISSION_TASK_TYPE_SMASH, m_Parent->GetLOT());
memberMissions->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, m_Parent->GetLOT(), skillID);
memberMissions->Progress(eMissionTaskType::SMASH, m_Parent->GetLOT());
memberMissions->Progress(eMissionTaskType::USE_SKILL, m_Parent->GetLOT(), skillID);
}
} else {
missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SMASH, m_Parent->GetLOT());
missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, m_Parent->GetLOT(), skillID);
missions->Progress(eMissionTaskType::SMASH, m_Parent->GetLOT());
missions->Progress(eMissionTaskType::USE_SKILL, m_Parent->GetLOT(), skillID);
}
}
}
@@ -747,22 +792,17 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
if (dZoneManager::Instance()->GetPlayerLoseCoinOnDeath()) {
auto* character = m_Parent->GetCharacter();
uint64_t coinsTotal = character->GetCoins();
const uint64_t minCoinsToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathMin;
if (coinsTotal >= minCoinsToLose) {
const uint64_t maxCoinsToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathMax;
const float coinPercentageToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathPercent;
if (coinsTotal > 0) {
uint64_t coinsToLoose = 1;
uint64_t coinsToLose = std::max(static_cast<uint64_t>(coinsTotal * coinPercentageToLose), minCoinsToLose);
coinsToLose = std::min(maxCoinsToLose, coinsToLose);
if (coinsTotal >= 200) {
float hundreth = (coinsTotal / 100.0f);
coinsToLoose = static_cast<int>(hundreth);
}
coinsTotal -= coinsToLose;
if (coinsToLoose > 10000) {
coinsToLoose = 10000;
}
coinsTotal -= coinsToLoose;
LootGenerator::Instance().DropLoot(m_Parent, m_Parent, -1, coinsToLoose, coinsToLoose);
LootGenerator::Instance().DropLoot(m_Parent, m_Parent, -1, coinsToLose, coinsToLose);
character->SetCoins(coinsTotal, eLootSourceType::LOOT_SOURCE_PICKUP);
}
}
@@ -772,7 +812,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
script->OnPlayerDied(zoneControl, m_Parent);
}
std::vector<Entity*> scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY);
std::vector<Entity*> scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY);
for (Entity* scriptEntity : scriptedActs) {
if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds
for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) {
@@ -792,12 +832,53 @@ void DestroyableComponent::SetFaction(int32_t factionID, bool ignoreChecks) {
AddFaction(factionID, ignoreChecks);
}
void DestroyableComponent::PushImmunity(int32_t stacks) {
m_ImmuneStacks += stacks;
}
void DestroyableComponent::SetStatusImmunity(
const eStateChangeType state,
const bool bImmuneToBasicAttack,
const bool bImmuneToDamageOverTime,
const bool bImmuneToKnockback,
const bool bImmuneToInterrupt,
const bool bImmuneToSpeed,
const bool bImmuneToImaginationGain,
const bool bImmuneToImaginationLoss,
const bool bImmuneToQuickbuildInterrupt,
const bool bImmuneToPullToPoint) {
void DestroyableComponent::PopImmunity(int32_t stacks) {
m_ImmuneStacks -= stacks;
if (state == eStateChangeType::POP) {
if (bImmuneToBasicAttack && m_ImmuneToBasicAttackCount > 0) m_ImmuneToBasicAttackCount -= 1;
if (bImmuneToDamageOverTime && m_ImmuneToDamageOverTimeCount > 0) m_ImmuneToDamageOverTimeCount -= 1;
if (bImmuneToKnockback && m_ImmuneToKnockbackCount > 0) m_ImmuneToKnockbackCount -= 1;
if (bImmuneToInterrupt && m_ImmuneToInterruptCount > 0) m_ImmuneToInterruptCount -= 1;
if (bImmuneToSpeed && m_ImmuneToSpeedCount > 0) m_ImmuneToSpeedCount -= 1;
if (bImmuneToImaginationGain && m_ImmuneToImaginationGainCount > 0) m_ImmuneToImaginationGainCount -= 1;
if (bImmuneToImaginationLoss && m_ImmuneToImaginationLossCount > 0) m_ImmuneToImaginationLossCount -= 1;
if (bImmuneToQuickbuildInterrupt && m_ImmuneToQuickbuildInterruptCount > 0) m_ImmuneToQuickbuildInterruptCount -= 1;
if (bImmuneToPullToPoint && m_ImmuneToPullToPointCount > 0) m_ImmuneToPullToPointCount -= 1;
} else if (state == eStateChangeType::PUSH){
if (bImmuneToBasicAttack) m_ImmuneToBasicAttackCount += 1;
if (bImmuneToDamageOverTime) m_ImmuneToDamageOverTimeCount += 1;
if (bImmuneToKnockback) m_ImmuneToKnockbackCount += 1;
if (bImmuneToInterrupt) m_ImmuneToInterruptCount += 1;
if (bImmuneToSpeed) m_ImmuneToSpeedCount += 1;
if (bImmuneToImaginationGain) m_ImmuneToImaginationGainCount += 1;
if (bImmuneToImaginationLoss) m_ImmuneToImaginationLossCount += 1;
if (bImmuneToQuickbuildInterrupt) m_ImmuneToQuickbuildInterruptCount += 1;
if (bImmuneToPullToPoint) m_ImmuneToPullToPointCount += 1;
}
GameMessages::SendSetStatusImmunity(
m_Parent->GetObjectID(), state, m_Parent->GetSystemAddress(),
bImmuneToBasicAttack,
bImmuneToDamageOverTime,
bImmuneToKnockback,
bImmuneToInterrupt,
bImmuneToSpeed,
bImmuneToImaginationGain,
bImmuneToImaginationLoss,
bImmuneToQuickbuildInterrupt,
bImmuneToPullToPoint
);
}
void DestroyableComponent::FixStats() {
@@ -900,3 +981,75 @@ void DestroyableComponent::FixStats() {
void DestroyableComponent::AddOnHitCallback(const std::function<void(Entity*)>& callback) {
m_OnHitCallbacks.push_back(callback);
}
void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source){
//check if this is a player:
if (m_Parent->IsPlayer()) {
//remove hardcore_lose_uscore_on_death_percent from the player's uscore:
auto* character = m_Parent->GetComponent<CharacterComponent>();
auto uscore = character->GetUScore();
auto uscoreToLose = uscore * (EntityManager::Instance()->GetHardcoreLoseUscoreOnDeathPercent() / 100);
character->SetUScore(uscore - uscoreToLose);
GameMessages::SendModifyLEGOScore(m_Parent, m_Parent->GetSystemAddress(), -uscoreToLose, eLootSourceType::LOOT_SOURCE_MISSION);
if (EntityManager::Instance()->GetHardcoreDropinventoryOnDeath()) {
//drop all items from inventory:
auto* inventory = m_Parent->GetComponent<InventoryComponent>();
if (inventory) {
//get the items inventory:
auto items = inventory->GetInventory(eInventoryType::ITEMS);
if (items){
auto itemMap = items->GetItems();
if (!itemMap.empty()){
for (const auto& item : itemMap) {
//drop the item:
if (!item.second) continue;
// don't drop the thinkng cap
if (item.second->GetLot() == 6086) continue;
GameMessages::SendDropClientLoot(m_Parent, source, item.second->GetLot(), 0, m_Parent->GetPosition(), item.second->GetCount());
item.second->SetCount(0, false, false);
}
EntityManager::Instance()->SerializeEntity(m_Parent);
}
}
}
}
//get character:
auto* chars = m_Parent->GetCharacter();
if (chars) {
auto coins = chars->GetCoins();
//lose all coins:
chars->SetCoins(0, eLootSourceType::LOOT_SOURCE_NONE);
//drop all coins:
GameMessages::SendDropClientLoot(m_Parent, source, LOT_NULL, coins, m_Parent->GetPosition());
}
// Reload the player since we can't normally reduce uscore from the server and we want the UI to update
// do this last so we don't get killed.... again
EntityManager::Instance()->DestructEntity(m_Parent);
EntityManager::Instance()->ConstructEntity(m_Parent);
return;
}
//award the player some u-score:
auto* player = EntityManager::Instance()->GetEntity(source);
if (player && player->IsPlayer()) {
auto* playerStats = player->GetComponent<CharacterComponent>();
if (playerStats) {
//get the maximum health from this enemy:
auto maxHealth = GetMaxHealth();
int uscore = maxHealth * EntityManager::Instance()->GetHardcoreUscoreEnemiesMultiplier();
playerStats->SetUScore(playerStats->GetUScore() + uscore);
GameMessages::SendModifyLEGOScore(player, player->GetSystemAddress(), uscore, eLootSourceType::LOOT_SOURCE_MISSION);
EntityManager::Instance()->SerializeEntity(m_Parent);
}
}
}

View File

@@ -6,6 +6,11 @@
#include "tinyxml2.h"
#include "Entity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
namespace CppScripts {
class Script;
}; //! namespace CppScripts
/**
* Represents the stats of an entity, for example its health, imagination and armor. Also handles factions, which
@@ -13,7 +18,7 @@
*/
class DestroyableComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_DESTROYABLE;
static const eReplicaComponentType ComponentType = eReplicaComponentType::DESTROYABLE;
DestroyableComponent(Entity* parentEntity);
~DestroyableComponent() override;
@@ -239,7 +244,7 @@ public:
* Sets the multiplier for the explosion that's visible when the bricks fly out when this entity is smashed
* @param value the multiplier for the explosion that's visible when the bricks fly out when this entity is smashed
*/
void SetExplodeFactor(float value);
void SetExplodeFactor(float value) { m_ExplodeFactor = value; };
/**
* Returns the current multiplier for explosions
@@ -392,16 +397,31 @@ public:
void Smash(LWOOBJID source, eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u"", uint32_t skillID = 0);
/**
* Pushes a layer of immunity to this entity, making it immune for longer
* @param stacks the amount of immunity to add
* Push or Pop a layer of status immunity to this entity
*/
void PushImmunity(int32_t stacks = 1);
void SetStatusImmunity(
const eStateChangeType state,
const bool bImmuneToBasicAttack = false,
const bool bImmuneToDamageOverTime = false,
const bool bImmuneToKnockback = false,
const bool bImmuneToInterrupt = false,
const bool bImmuneToSpeed = false,
const bool bImmuneToImaginationGain = false,
const bool bImmuneToImaginationLoss = false,
const bool bImmuneToQuickbuildInterrupt = false,
const bool bImmuneToPullToPoint = false
);
/**
* Pops layers of immunity, making it immune for less longer
* @param stacks the number of layers of immunity to remove
*/
void PopImmunity(int32_t stacks = 1);
// Getters for status immunities
const bool GetImmuneToBasicAttack() {return m_ImmuneToBasicAttackCount > 0;};
const bool GetImmuneToDamageOverTime() {return m_ImmuneToDamageOverTimeCount > 0;};
const bool GetImmuneToKnockback() {return m_ImmuneToKnockbackCount > 0;};
const bool GetImmuneToInterrupt() {return m_ImmuneToInterruptCount > 0;};
const bool GetImmuneToSpeed() {return m_ImmuneToSpeedCount > 0;};
const bool GetImmuneToImaginationGain() {return m_ImmuneToImaginationGainCount > 0;};
const bool GetImmuneToImaginationLoss() {return m_ImmuneToImaginationLossCount > 0;};
const bool GetImmuneToQuickbuildInterrupt() {return m_ImmuneToQuickbuildInterruptCount > 0;};
const bool GetImmuneToPullToPoint() {return m_ImmuneToPullToPointCount > 0;};
/**
* Utility to reset all stats to the default stats based on items and completed missions
@@ -414,6 +434,28 @@ public:
*/
void AddOnHitCallback(const std::function<void(Entity*)>& callback);
/**
* Pushes a faction back to the list of factions.
* @param value Faction to add to list.
*
* This method should only be used for testing. Use AddFaction(int32_t, bool) for adding a faction properly.
*/
void AddFactionNoLookup(int32_t faction) { m_FactionIDs.push_back(faction); };
/**
* Notify subscribed scripts of Damage actions.
*
* @param attacker The attacking Entity
* @param damage The amount of damage that was done
*/
void NotifySubscribers(Entity* attacker, uint32_t damage);
void Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd);
void Unsubscribe(LWOOBJID scriptObjId);
// handle hardcode mode drops
void DoHardcoreModeDrops(const LWOOBJID source);
private:
/**
* Whether or not the health should be serialized
@@ -470,11 +512,6 @@ private:
*/
uint32_t m_AttacksToBlock;
/**
* The layers of immunity this entity has left
*/
int32_t m_ImmuneStacks;
/**
* The amount of damage that should be reduced from every attack
*/
@@ -549,6 +586,24 @@ private:
* The list of callbacks that will be called when this entity gets hit
*/
std::vector<std::function<void(Entity*)>> m_OnHitCallbacks;
/**
* The list of scripts subscribed to this components actions
*/
std::map<LWOOBJID, CppScripts::Script*> m_SubscribedScripts;
/**
* status immunity counters
*/
uint32_t m_ImmuneToBasicAttackCount;
uint32_t m_ImmuneToDamageOverTimeCount;
uint32_t m_ImmuneToKnockbackCount;
uint32_t m_ImmuneToInterruptCount;
uint32_t m_ImmuneToSpeedCount;
uint32_t m_ImmuneToImaginationGainCount;
uint32_t m_ImmuneToImaginationLossCount;
uint32_t m_ImmuneToQuickbuildInterruptCount;
uint32_t m_ImmuneToPullToPointCount;
};
#endif // DESTROYABLECOMPONENT_H

View File

@@ -27,8 +27,16 @@
#include "dConfig.h"
#include "eItemType.h"
#include "eUnequippableActiveType.h"
#include "CppScripts.h"
#include "eMissionTaskType.h"
InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent) {
#include "CDComponentsRegistryTable.h"
#include "CDInventoryComponentTable.h"
#include "CDScriptComponentTable.h"
#include "CDObjectSkillsTable.h"
#include "CDSkillBehaviorTable.h"
InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document): Component(parent) {
this->m_Dirty = true;
this->m_Equipped = {};
this->m_Pushed = {};
@@ -45,10 +53,10 @@ InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* do
return;
}
auto* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
const auto componentId = compRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_INVENTORY);
auto* compRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
const auto componentId = compRegistryTable->GetByIDAndType(lot, eReplicaComponentType::INVENTORY);
auto* inventoryComponentTable = CDClientManager::Instance()->GetTable<CDInventoryComponentTable>("InventoryComponent");
auto* inventoryComponentTable = CDClientManager::Instance().GetTable<CDInventoryComponentTable>();
auto items = inventoryComponentTable->Query([=](const CDInventoryComponent entry) { return entry.id == componentId; });
auto slot = 0u;
@@ -179,7 +187,7 @@ void InventoryComponent::AddItem(
inventoryType = Inventory::FindInventoryTypeForLot(lot);
}
auto* missions = static_cast<MissionComponent*>(this->m_Parent->GetComponent(COMPONENT_TYPE_MISSION));
auto* missions = static_cast<MissionComponent*>(this->m_Parent->GetComponent(eReplicaComponentType::MISSION));
auto* inventory = GetInventory(inventoryType);
@@ -195,7 +203,7 @@ void InventoryComponent::AddItem(
auto* item = new Item(lot, inventory, slot, count, config, parent, showFlyingLoot, isModMoveAndEquip, subKey, bound, lootSourceType);
if (missions != nullptr && !IsTransferInventory(inventoryType)) {
missions->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, lot, LWOOBJID_EMPTY, "", count, IsTransferInventory(inventorySourceType));
missions->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", count, IsTransferInventory(inventorySourceType));
}
return;
@@ -209,9 +217,11 @@ void InventoryComponent::AddItem(
auto stack = static_cast<uint32_t>(info.stackSize);
bool isBrick = inventoryType == eInventoryType::BRICKS || (stack == 0 && info.itemType == 1);
// info.itemType of 1 is item type brick
if (inventoryType == eInventoryType::BRICKS || (stack == 0 && info.itemType == 1)) {
stack = 999;
if (isBrick) {
stack = UINT32_MAX;
} else if (stack == 0) {
stack = 1;
}
@@ -232,7 +242,8 @@ void InventoryComponent::AddItem(
}
}
while (left > 0) {
// If we have some leftover and we aren't bricks, make a new stack
while (left > 0 && (!isBrick || (isBrick && !existing))) {
const auto size = std::min(left, stack);
left -= size;
@@ -280,7 +291,7 @@ void InventoryComponent::AddItem(
}
if (missions != nullptr && !IsTransferInventory(inventoryType)) {
missions->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, lot, LWOOBJID_EMPTY, "", count - outOfSpace, IsTransferInventory(inventorySourceType));
missions->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", count - outOfSpace, IsTransferInventory(inventorySourceType));
}
}
@@ -327,7 +338,9 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in
const auto lot = item->GetLot();
if (item->GetConfig().empty() && !item->GetBound() || (item->GetBound() && item->GetInfo().isBOP)) {
const auto subkey = item->GetSubKey();
if (subkey == LWOOBJID_EMPTY && item->GetConfig().empty() && (!item->GetBound() || (item->GetBound() && item->GetInfo().isBOP))) {
auto left = std::min<uint32_t>(count, origin->GetLotCount(lot));
while (left > 0) {
@@ -358,7 +371,7 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in
const auto delta = std::min<uint32_t>(item->GetCount(), count);
AddItem(lot, delta, eLootSourceType::LOOT_SOURCE_NONE, inventory, config, LWOOBJID_EMPTY, showFlyingLot, isModMoveAndEquip, LWOOBJID_EMPTY, origin->GetType(), 0, item->GetBound(), preferredSlot);
AddItem(lot, delta, eLootSourceType::LOOT_SOURCE_NONE, inventory, config, LWOOBJID_EMPTY, showFlyingLot, isModMoveAndEquip, subkey, origin->GetType(), 0, item->GetBound(), preferredSlot);
item->SetCount(item->GetCount() - delta, false, false);
}
@@ -367,7 +380,7 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in
if (missionComponent != nullptr) {
if (IsTransferInventory(inventory)) {
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, lot, LWOOBJID_EMPTY, "", -static_cast<int32_t>(count));
missionComponent->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", -static_cast<int32_t>(count));
}
}
}
@@ -605,16 +618,17 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) {
return;
}
std::vector<Inventory*> inventories;
std::vector<Inventory*> inventoriesToSave;
// Need to prevent some transfer inventories from being saved
for (const auto& pair : this->m_Inventories) {
auto* inventory = pair.second;
if (inventory->GetType() == VENDOR_BUYBACK) {
if (inventory->GetType() == VENDOR_BUYBACK || inventory->GetType() == eInventoryType::MODELS_IN_BBB) {
continue;
}
inventories.push_back(inventory);
inventoriesToSave.push_back(inventory);
}
inventoryElement->SetAttribute("csl", m_Consumable);
@@ -629,7 +643,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) {
bags->DeleteChildren();
for (const auto* inventory : inventories) {
for (const auto* inventory : inventoriesToSave) {
auto* bag = document->NewElement("b");
bag->SetAttribute("t", inventory->GetType());
@@ -648,7 +662,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) {
items->DeleteChildren();
for (auto* inventory : inventories) {
for (auto* inventory : inventoriesToSave) {
if (inventory->GetSize() == 0) {
continue;
}
@@ -810,7 +824,7 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) {
if (character != nullptr && !skipChecks) {
// Hacky proximity rocket
if (item->GetLot() == 6416) {
const auto rocketLauchPads = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_ROCKET_LAUNCH);
const auto rocketLauchPads = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::ROCKET_LAUNCH);
const auto position = m_Parent->GetPosition();
@@ -834,9 +848,9 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) {
const auto type = static_cast<eItemType>(item->GetInfo().itemType);
if (!building && (item->GetLot() == 6086 || type == eItemType::ITEM_TYPE_LOOT_MODEL || type == eItemType::ITEM_TYPE_VEHICLE)) return;
if (!building && (item->GetLot() == 6086 || type == eItemType::LOOT_MODEL || type == eItemType::VEHICLE)) return;
if (type != eItemType::ITEM_TYPE_LOOT_MODEL && type != eItemType::ITEM_TYPE_MODEL) {
if (type != eItemType::LOOT_MODEL && type != eItemType::MODEL) {
if (!item->GetBound() && !item->GetPreconditionExpression()->Check(m_Parent)) {
return;
}
@@ -861,6 +875,8 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) {
AddItemSkills(item->GetLot());
EquipScripts(item);
EntityManager::Instance()->SerializeEntity(m_Parent);
}
@@ -889,6 +905,8 @@ void InventoryComponent::UnEquipItem(Item* item) {
PurgeProxies(item);
UnequipScripts(item);
EntityManager::Instance()->SerializeEntity(m_Parent);
// Trigger property event
@@ -898,6 +916,37 @@ void InventoryComponent::UnEquipItem(Item* item) {
}
}
void InventoryComponent::EquipScripts(Item* equippedItem) {
CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
if (!compRegistryTable) return;
int32_t scriptComponentID = compRegistryTable->GetByIDAndType(equippedItem->GetLot(), eReplicaComponentType::SCRIPT, -1);
if (scriptComponentID > -1) {
CDScriptComponentTable* scriptCompTable = CDClientManager::Instance().GetTable<CDScriptComponentTable>();
CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID);
auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData.script_name);
if (!itemScript) {
Game::logger->Log("InventoryComponent", "null script?");
}
itemScript->OnFactionTriggerItemEquipped(m_Parent, equippedItem->GetId());
}
}
void InventoryComponent::UnequipScripts(Item* unequippedItem) {
CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
if (!compRegistryTable) return;
int32_t scriptComponentID = compRegistryTable->GetByIDAndType(unequippedItem->GetLot(), eReplicaComponentType::SCRIPT, -1);
if (scriptComponentID > -1) {
CDScriptComponentTable* scriptCompTable = CDClientManager::Instance().GetTable<CDScriptComponentTable>();
CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID);
auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData.script_name);
if (!itemScript) {
Game::logger->Log("InventoryComponent", "null script?");
}
itemScript->OnFactionTriggerItemUnequipped(m_Parent, unequippedItem->GetId());
}
}
void InventoryComponent::HandlePossession(Item* item) {
auto* characterComponent = m_Parent->GetComponent<CharacterComponent>();
if (!characterComponent) return;
@@ -917,7 +966,7 @@ void InventoryComponent::HandlePossession(Item* item) {
return;
}
GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStunState::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStateChangeType::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
// Set the mount Item ID so that we know what were handling
possessorComponent->SetMountItemID(item->GetId());
@@ -985,6 +1034,7 @@ void InventoryComponent::ApplyBuff(Item* item) const {
}
}
// TODO Something needs to send the remove buff GameMessage as well when it is unequipping items that would remove buffs.
void InventoryComponent::RemoveBuff(Item* item) const {
const auto buffs = FindBuffs(item, false);
@@ -1153,20 +1203,20 @@ void InventoryComponent::RemoveItemSkills(const LOT lot) {
}
}
void InventoryComponent::TriggerPassiveAbility(PassiveAbilityTrigger trigger) {
void InventoryComponent::TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target) {
for (auto* set : m_Itemsets) {
set->TriggerPassiveAbility(trigger);
set->TriggerPassiveAbility(trigger, target);
}
}
bool InventoryComponent::HasAnyPassive(const std::vector<ItemSetPassiveAbilityID>& passiveIDs, int32_t equipmentRequirement) const {
bool InventoryComponent::HasAnyPassive(const std::vector<eItemSetPassiveAbilityID>& passiveIDs, int32_t equipmentRequirement) const {
for (auto* set : m_Itemsets) {
if (set->GetEquippedCount() < equipmentRequirement) {
continue;
}
// Check if the set has any of the passive abilities
if (std::find(passiveIDs.begin(), passiveIDs.end(), static_cast<ItemSetPassiveAbilityID>(set->GetID())) != passiveIDs.end()) {
if (std::find(passiveIDs.begin(), passiveIDs.end(), static_cast<eItemSetPassiveAbilityID>(set->GetID())) != passiveIDs.end()) {
return true;
}
}
@@ -1242,15 +1292,15 @@ void InventoryComponent::RemoveDatabasePet(LWOOBJID id) {
BehaviorSlot InventoryComponent::FindBehaviorSlot(const eItemType type) {
switch (type) {
case eItemType::ITEM_TYPE_HAT:
case eItemType::HAT:
return BehaviorSlot::Head;
case eItemType::ITEM_TYPE_NECK:
case eItemType::NECK:
return BehaviorSlot::Neck;
case eItemType::ITEM_TYPE_LEFT_HAND:
case eItemType::LEFT_HAND:
return BehaviorSlot::Offhand;
case eItemType::ITEM_TYPE_RIGHT_HAND:
case eItemType::RIGHT_HAND:
return BehaviorSlot::Primary;
case eItemType::ITEM_TYPE_CONSUMABLE:
case eItemType::CONSUMABLE:
return BehaviorSlot::Consumable;
default:
return BehaviorSlot::Invalid;
@@ -1258,11 +1308,11 @@ BehaviorSlot InventoryComponent::FindBehaviorSlot(const eItemType type) {
}
bool InventoryComponent::IsTransferInventory(eInventoryType type) {
return type == VENDOR_BUYBACK || type == VAULT_ITEMS || type == VAULT_MODELS || type == TEMP_ITEMS || type == TEMP_MODELS;
return type == VENDOR_BUYBACK || type == VAULT_ITEMS || type == VAULT_MODELS || type == TEMP_ITEMS || type == TEMP_MODELS || type == MODELS_IN_BBB;
}
uint32_t InventoryComponent::FindSkill(const LOT lot) {
auto* table = CDClientManager::Instance()->GetTable<CDObjectSkillsTable>("ObjectSkills");
auto* table = CDClientManager::Instance().GetTable<CDObjectSkillsTable>();
const auto results = table->Query([=](const CDObjectSkills& entry) {
return entry.objectTemplate == static_cast<unsigned int>(lot);
@@ -1280,14 +1330,14 @@ uint32_t InventoryComponent::FindSkill(const LOT lot) {
std::vector<uint32_t> InventoryComponent::FindBuffs(Item* item, bool castOnEquip) const {
std::vector<uint32_t> buffs;
if (item == nullptr) return buffs;
auto* table = CDClientManager::Instance()->GetTable<CDObjectSkillsTable>("ObjectSkills");
auto* behaviors = CDClientManager::Instance()->GetTable<CDSkillBehaviorTable>("SkillBehavior");
auto* table = CDClientManager::Instance().GetTable<CDObjectSkillsTable>();
auto* behaviors = CDClientManager::Instance().GetTable<CDSkillBehaviorTable>();
const auto results = table->Query([=](const CDObjectSkills& entry) {
return entry.objectTemplate == static_cast<unsigned int>(item->GetLot());
});
auto* missions = static_cast<MissionComponent*>(m_Parent->GetComponent(COMPONENT_TYPE_MISSION));
auto* missions = static_cast<MissionComponent*>(m_Parent->GetComponent(eReplicaComponentType::MISSION));
for (const auto& result : results) {
if (result.castOnType == 1) {
@@ -1300,7 +1350,7 @@ std::vector<uint32_t> InventoryComponent::FindBuffs(Item* item, bool castOnEquip
}
if (missions != nullptr && castOnEquip) {
missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, result.skillID);
missions->Progress(eMissionTaskType::USE_SKILL, result.skillID);
}
// If item is not a proxy, add its buff to the added buffs.

View File

@@ -17,8 +17,10 @@
#include "DatabasePet.h"
#include "Component.h"
#include "ItemSetPassiveAbility.h"
#include "ItemSetPassiveAbilityID.h"
#include "eItemSetPassiveAbilityID.h"
#include "PossessorComponent.h"
#include "eInventoryType.h"
#include "eReplicaComponentType.h"
class Entity;
class ItemSet;
@@ -35,7 +37,7 @@ enum class eItemType : int32_t;
class InventoryComponent : public Component
{
public:
static const uint32_t ComponentType = COMPONENT_TYPE_INVENTORY;
static const eReplicaComponentType ComponentType = eReplicaComponentType::INVENTORY;
explicit InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document = nullptr);
void Update(float deltaTime) override;
@@ -282,7 +284,7 @@ public:
* Triggers one of the passive abilities from the equipped item set
* @param trigger the trigger to fire
*/
void TriggerPassiveAbility(PassiveAbilityTrigger trigger);
void TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target = nullptr);
/**
* Returns if the entity has any of the passed passive abilities equipped
@@ -290,7 +292,7 @@ public:
* @param equipmentRequirement the number of equipment required to be allowed to have the ability
* @return if the entity has any of the passed passive abilities equipped
*/
bool HasAnyPassive(const std::vector<ItemSetPassiveAbilityID>& passiveIDs, int32_t equipmentRequirement) const;
bool HasAnyPassive(const std::vector<eItemSetPassiveAbilityID>& passiveIDs, int32_t equipmentRequirement) const;
/**
* Despawns the currently active pet, if any
@@ -351,6 +353,20 @@ public:
*/
static uint32_t FindSkill(LOT lot);
/**
* Call this when you equip an item. This calls OnFactionTriggerItemEquipped for any scripts found on the items.
*
* @param equippedItem The item script to lookup and call equip on
*/
void EquipScripts(Item* equippedItem);
/**
* Call this when you unequip an item. This calls OnFactionTriggerItemUnequipped for any scripts found on the items.
*
* @param unequippedItem The item script to lookup and call unequip on
*/
void UnequipScripts(Item* unequippedItem);
~InventoryComponent() override;
private:

View File

@@ -2,6 +2,7 @@
#include "Component.h"
#include "Entity.h"
#include "eReplicaComponentType.h"
/**
* Component that handles the LOT that is shown in the LUP exhibit in the LUP world. Works by setting a timer and
@@ -10,7 +11,7 @@
class LUPExhibitComponent : public Component
{
public:
static const uint32_t ComponentType = COMPONENT_TYPE_EXHIBIT;
static const eReplicaComponentType ComponentType = eReplicaComponentType::EXHIBIT;
LUPExhibitComponent(Entity* parent);
~LUPExhibitComponent();

View File

@@ -4,9 +4,13 @@
#include "CharacterComponent.h"
#include "tinyxml2.h"
#include "CDRewardsTable.h"
LevelProgressionComponent::LevelProgressionComponent(Entity* parent) : Component(parent) {
m_Parent = parent;
m_Level = 1;
m_SpeedBase = 500.0f;
m_CharacterVersion = eCharacterVersion::LIVE;
}
void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
@@ -16,7 +20,8 @@ void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
return;
}
level->SetAttribute("l", m_Level);
level->SetAttribute("sb", m_SpeedBase);
level->SetAttribute("cv", static_cast<uint32_t>(m_CharacterVersion));
}
void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
@@ -26,7 +31,10 @@ void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
return;
}
level->QueryAttribute("l", &m_Level);
level->QueryAttribute("sb", &m_SpeedBase);
uint32_t characterVersion;
level->QueryAttribute("cv", &characterVersion);
m_CharacterVersion = static_cast<eCharacterVersion>(characterVersion);
}
void LevelProgressionComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
@@ -36,7 +44,7 @@ void LevelProgressionComponent::Serialize(RakNet::BitStream* outBitStream, bool
}
void LevelProgressionComponent::HandleLevelUp() {
auto* rewardsTable = CDClientManager::Instance()->GetTable<CDRewardsTable>("Rewards");
auto* rewardsTable = CDClientManager::Instance().GetTable<CDRewardsTable>();
const auto& rewards = rewardsTable->GetByLevelID(m_Level);
bool rewardingItem = rewards.size() > 0;
@@ -60,7 +68,8 @@ void LevelProgressionComponent::HandleLevelUp() {
}
break;
case 9:
controllablePhysicsComponent->SetSpeedMultiplier(static_cast<float>(reward->value) / 500.0f);
SetSpeedBase(static_cast<float>(reward->value) );
controllablePhysicsComponent->SetSpeedMultiplier(GetSpeedBase() / 500.0f);
break;
case 11:
case 12:
@@ -72,3 +81,9 @@ void LevelProgressionComponent::HandleLevelUp() {
// Tell the client we have finished sending level rewards.
if (rewardingItem) GameMessages::NotifyLevelRewards(m_Parent->GetObjectID(), m_Parent->GetSystemAddress(), m_Level, !rewardingItem);
}
void LevelProgressionComponent::SetRetroactiveBaseSpeed(){
if (m_Level >= 20) m_SpeedBase = 525.0f;
auto* controllablePhysicsComponent = m_Parent->GetComponent<ControllablePhysicsComponent>();
if (controllablePhysicsComponent) controllablePhysicsComponent->SetSpeedMultiplier(m_SpeedBase / 500.0f);
}

View File

@@ -3,14 +3,17 @@
#include "Entity.h"
#include "GameMessages.h"
#include "Component.h"
#include "eCharacterVersion.h"
#include "eReplicaComponentType.h"
/**
* Component that handles level progression and serilization.
*
*/
class LevelProgressionComponent : public Component {
public:
static const uint32_t ComponentType = eReplicaComponentType::COMPONENT_TYPE_LEVEL_PROGRESSION;
static const eReplicaComponentType ComponentType = eReplicaComponentType::LEVEL_PROGRESSION;
/**
* Constructor for this component
@@ -44,11 +47,40 @@ public:
*/
void SetLevel(uint32_t level) { m_Level = level; m_DirtyLevelInfo = true; }
/**
* Gets the current Speed Base of the entity
* @return the current Speed Base of the entity
*/
const uint32_t GetSpeedBase() const { return m_SpeedBase; }
/**
* Sets the Speed Base of the entity
* @param SpeedBase the Speed Base to set
*/
void SetSpeedBase(uint32_t SpeedBase) { m_SpeedBase = SpeedBase; }
/**
* Gives the player rewards for the last level that they leveled up from
*/
void HandleLevelUp();
/**
* Gets the current Character Version of the entity
* @return the current Character Version of the entity
*/
const eCharacterVersion GetCharacterVersion() const { return m_CharacterVersion; }
/**
* Sets the Character Version of the entity
* @param CharacterVersion the Character Version to set
*/
void SetCharacterVersion(eCharacterVersion CharacterVersion) { m_CharacterVersion = CharacterVersion; }
/**
* Set the Base Speed retroactively of the entity
*/
void SetRetroactiveBaseSpeed();
private:
/**
* whether the level is dirty
@@ -59,4 +91,15 @@ private:
* Level of the entity
*/
uint32_t m_Level;
/**
* The base speed of the entity
*/
float m_SpeedBase;
/**
* The Character format version
*/
eCharacterVersion m_CharacterVersion;
};

View File

@@ -17,10 +17,12 @@
#include "dZoneManager.h"
#include "Mail.h"
#include "MissionPrerequisites.h"
#include "AchievementCacheKey.h"
#include "eMissionState.h"
// MARK: Mission Component
std::unordered_map<size_t, std::vector<uint32_t>> MissionComponent::m_AchievementCache = {};
std::unordered_map<AchievementCacheKey, std::vector<uint32_t>> MissionComponent::m_AchievementCache = {};
//! Initializer
MissionComponent::MissionComponent(Entity* parent) : Component(parent) {
@@ -52,11 +54,11 @@ Mission* MissionComponent::GetMission(const uint32_t missionId) const {
}
MissionState MissionComponent::GetMissionState(const uint32_t missionId) const {
eMissionState MissionComponent::GetMissionState(const uint32_t missionId) const {
auto* mission = GetMission(missionId);
if (mission == nullptr) {
return CanAccept(missionId) ? MissionState::MISSION_STATE_AVAILABLE : MissionState::MISSION_STATE_UNKNOWN;
return CanAccept(missionId) ? eMissionState::AVAILABLE : eMissionState::UNKNOWN;
}
return mission->GetMissionState();
@@ -142,7 +144,7 @@ void MissionComponent::RemoveMission(uint32_t missionId) {
m_Missions.erase(missionId);
}
void MissionComponent::Progress(MissionTaskType type, int32_t value, LWOOBJID associate, const std::string& targets, int32_t count, bool ignoreAchievements) {
void MissionComponent::Progress(eMissionTaskType type, int32_t value, LWOOBJID associate, const std::string& targets, int32_t count, bool ignoreAchievements) {
for (const auto& pair : m_Missions) {
auto* mission = pair.second;
@@ -214,7 +216,7 @@ void MissionComponent::ForceProgressTaskType(const uint32_t missionId, const uin
}
for (auto* element : mission->GetTasks()) {
if (element->GetType() != static_cast<MissionTaskType>(taskType)) continue;
if (element->GetType() != static_cast<eMissionTaskType>(taskType)) continue;
element->AddProgress(value);
}
@@ -252,7 +254,7 @@ void MissionComponent::ForceProgressValue(uint32_t missionId, uint32_t taskType,
}
for (auto* element : mission->GetTasks()) {
if (element->GetType() != static_cast<MissionTaskType>(taskType) || !element->InAllTargets(value)) continue;
if (element->GetType() != static_cast<eMissionTaskType>(taskType) || !element->InAllTargets(value)) continue;
element->AddProgress(1);
}
@@ -263,7 +265,7 @@ void MissionComponent::ForceProgressValue(uint32_t missionId, uint32_t taskType,
}
bool MissionComponent::GetMissionInfo(uint32_t missionId, CDMissions& result) {
auto* missionsTable = CDClientManager::Instance()->GetTable<CDMissionsTable>("Missions");
auto* missionsTable = CDClientManager::Instance().GetTable<CDMissionsTable>();
const auto missions = missionsTable->Query([=](const CDMissions& entry) {
return entry.id == static_cast<int>(missionId);
@@ -280,7 +282,7 @@ bool MissionComponent::GetMissionInfo(uint32_t missionId, CDMissions& result) {
#define MISSION_NEW_METHOD
bool MissionComponent::LookForAchievements(MissionTaskType type, int32_t value, bool progress, LWOOBJID associate, const std::string& targets, int32_t count) {
bool MissionComponent::LookForAchievements(eMissionTaskType type, int32_t value, bool progress, LWOOBJID associate, const std::string& targets, int32_t count) {
#ifdef MISSION_NEW_METHOD
// Query for achievments, using the cache
const auto& result = QueryAchievements(type, value, targets);
@@ -317,8 +319,8 @@ bool MissionComponent::LookForAchievements(MissionTaskType type, int32_t value,
return any;
#else
auto* missionTasksTable = CDClientManager::Instance()->GetTable<CDMissionTasksTable>("MissionTasks");
auto* missionsTable = CDClientManager::Instance()->GetTable<CDMissionsTable>("Missions");
auto* missionTasksTable = CDClientManager::Instance().GetTable<CDMissionTasksTable>();
auto* missionsTable = CDClientManager::Instance().GetTable<CDMissionsTable>();
auto tasks = missionTasksTable->Query([=](const CDMissionTasks& entry) {
return entry.taskType == static_cast<unsigned>(type);
@@ -389,14 +391,14 @@ bool MissionComponent::LookForAchievements(MissionTaskType type, int32_t value,
#endif
}
const std::vector<uint32_t>& MissionComponent::QueryAchievements(MissionTaskType type, int32_t value, const std::string targets) {
const std::vector<uint32_t>& MissionComponent::QueryAchievements(eMissionTaskType type, int32_t value, const std::string targets) {
// Create a hash which represent this query for achievements
size_t hash = 0;
GeneralUtils::hash_combine(hash, type);
GeneralUtils::hash_combine(hash, value);
GeneralUtils::hash_combine(hash, targets);
AchievementCacheKey toFind;
toFind.SetType(type);
toFind.SetValue(value);
toFind.SetTargets(targets);
const std::unordered_map<size_t, std::vector<uint32_t>>::iterator& iter = m_AchievementCache.find(hash);
const auto& iter = m_AchievementCache.find(toFind);
// Check if this query is cached
if (iter != m_AchievementCache.end()) {
@@ -404,8 +406,8 @@ const std::vector<uint32_t>& MissionComponent::QueryAchievements(MissionTaskType
}
// Find relevent tables
auto* missionTasksTable = CDClientManager::Instance()->GetTable<CDMissionTasksTable>("MissionTasks");
auto* missionsTable = CDClientManager::Instance()->GetTable<CDMissionsTable>("Missions");
auto* missionTasksTable = CDClientManager::Instance().GetTable<CDMissionTasksTable>();
auto* missionsTable = CDClientManager::Instance().GetTable<CDMissionsTable>();
std::vector<uint32_t> result;
@@ -447,11 +449,9 @@ const std::vector<uint32_t>& MissionComponent::QueryAchievements(MissionTaskType
}
}
}
// Insert into cache
m_AchievementCache.insert_or_assign(hash, result);
return m_AchievementCache.find(hash)->second;
m_AchievementCache.insert_or_assign(toFind, result);
return m_AchievementCache.find(toFind)->second;
}
bool MissionComponent::RequiresItem(const LOT lot) {
@@ -485,7 +485,7 @@ bool MissionComponent::RequiresItem(const LOT lot) {
}
for (auto* task : mission->GetTasks()) {
if (task->IsComplete() || task->GetType() != MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION) {
if (task->IsComplete() || task->GetType() != eMissionTaskType::GATHER) {
continue;
}
@@ -497,7 +497,7 @@ bool MissionComponent::RequiresItem(const LOT lot) {
}
}
const auto required = LookForAchievements(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, lot, false);
const auto required = LookForAchievements(eMissionTaskType::GATHER, lot, false);
return required;
}

View File

@@ -16,15 +16,18 @@
#include "CDClientManager.h"
#include "CDMissionsTable.h"
#include "Component.h"
#include "eReplicaComponentType.h"
class AchievementCacheKey;
/**
* The mission inventory of an entity. Tracks mission state for each mission that can be accepted and allows for
* progression of each of the mission task types (see MissionTaskType).
* progression of each of the mission task types (see eMissionTaskType).
*/
class MissionComponent : public Component
{
public:
static const uint32_t ComponentType = COMPONENT_TYPE_MISSION;
static const eReplicaComponentType ComponentType = eReplicaComponentType::MISSION;
explicit MissionComponent(Entity* parent);
~MissionComponent() override;
@@ -50,7 +53,7 @@ public:
* @param missionId the ID of the mission to get the mission state for
* @return the mission state of the mission specified by the ID
*/
MissionState GetMissionState(uint32_t missionId) const;
eMissionState GetMissionState(uint32_t missionId) const;
/**
* Checks if the entity has all the requirements for accepting the mission specified by the ID.
@@ -91,7 +94,7 @@ public:
* @param count the number to progress by, for example the number of items
* @param ignoreAchievements do not progress achievements
*/
void Progress(MissionTaskType type, int32_t value, LWOOBJID associate = 0, const std::string& targets = "", int32_t count = 1, bool ignoreAchievements = false);
void Progress(eMissionTaskType type, int32_t value, LWOOBJID associate = 0, const std::string& targets = "", int32_t count = 1, bool ignoreAchievements = false);
/**
* Forces progression for a mission and task, ignoring checks
@@ -138,7 +141,7 @@ public:
* @param count the number of values to progress by (differs by task type)
* @return true if a achievement was accepted, false otherwise
*/
bool LookForAchievements(MissionTaskType type, int32_t value, bool progress = true, LWOOBJID associate = LWOOBJID_EMPTY, const std::string& targets = "", int32_t count = 1);
bool LookForAchievements(eMissionTaskType type, int32_t value, bool progress = true, LWOOBJID associate = LWOOBJID_EMPTY, const std::string& targets = "", int32_t count = 1);
/**
* Checks if there's a mission active that requires the collection of the specified LOT
@@ -186,13 +189,13 @@ private:
* @param targets optional targets to progress with
* @return list of mission IDs (achievements) that can be progressed for the given parameters
*/
static const std::vector<uint32_t>& QueryAchievements(MissionTaskType type, int32_t value, const std::string targets);
static const std::vector<uint32_t>& QueryAchievements(eMissionTaskType type, int32_t value, const std::string targets);
/**
* As achievements can be hard to query, we here store a list of all the mission IDs that can be unlocked for a
* combination of tasks and values, so that they can be easily re-queried later
*/
static std::unordered_map<size_t, std::vector<uint32_t>> m_AchievementCache;
static std::unordered_map<AchievementCacheKey, std::vector<uint32_t>> m_AchievementCache;
/**
* Order of missions in the UI. This value is incremented by 1

View File

@@ -14,6 +14,9 @@
#include "dLogger.h"
#include "Game.h"
#include "MissionPrerequisites.h"
#include "eMissionState.h"
#include "CDComponentsRegistryTable.h"
OfferedMission::OfferedMission(const uint32_t missionId, const bool offersMission, const bool acceptsMission) {
this->missionId = missionId;
@@ -37,15 +40,15 @@ bool OfferedMission::GetAcceptMission() const {
//------------------------ MissionOfferComponent below ------------------------
MissionOfferComponent::MissionOfferComponent(Entity* parent, const LOT parentLot) : Component(parent) {
auto* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
auto* compRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
auto value = compRegistryTable->GetByIDAndType(parentLot, COMPONENT_TYPE_MISSION_OFFER, -1);
auto value = compRegistryTable->GetByIDAndType(parentLot, eReplicaComponentType::MISSION_OFFER, -1);
if (value != -1) {
const uint32_t componentId = value;
// Now lookup the missions in the MissionNPCComponent table
auto* missionNpcComponentTable = CDClientManager::Instance()->GetTable<CDMissionNPCComponentTable>("MissionNPCComponent");
auto* missionNpcComponentTable = CDClientManager::Instance().GetTable<CDMissionNPCComponentTable>();
auto missions = missionNpcComponentTable->Query([=](const CDMissionNPCComponent& entry) {
return entry.id == static_cast<unsigned>(componentId);
@@ -76,7 +79,7 @@ void MissionOfferComponent::OnUse(Entity* originator) {
void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifiedMissionId) {
// First, get the entity's MissionComponent. If there is not one, then we cannot offer missions to this entity.
auto* missionComponent = static_cast<MissionComponent*>(entity->GetComponent(COMPONENT_TYPE_MISSION));
auto* missionComponent = static_cast<MissionComponent*>(entity->GetComponent(eReplicaComponentType::MISSION));
if (!missionComponent) {
Game::logger->Log("MissionOfferComponent", "Unable to get mission component for Entity %llu", entity->GetObjectID());
@@ -170,10 +173,10 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi
for (const auto sample : randomMissionPool) {
const auto state = missionComponent->GetMissionState(sample);
if (state == MissionState::MISSION_STATE_ACTIVE ||
state == MissionState::MISSION_STATE_COMPLETE_ACTIVE ||
state == MissionState::MISSION_STATE_READY_TO_COMPLETE ||
state == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE ||
if (state == eMissionState::ACTIVE ||
state == eMissionState::COMPLETE_ACTIVE ||
state == eMissionState::READY_TO_COMPLETE ||
state == eMissionState::COMPLETE_READY_TO_COMPLETE ||
sample == specifiedMissionId) {
mission = missionComponent->GetMission(sample);

View File

@@ -10,6 +10,7 @@
#include "Component.h"
#include <vector>
#include <stdint.h>
#include "eReplicaComponentType.h"
class Entity;
@@ -60,7 +61,7 @@ private:
*/
class MissionOfferComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_MISSION_OFFER;
static const eReplicaComponentType ComponentType = eReplicaComponentType::MISSION_OFFER;
MissionOfferComponent(Entity* parent, LOT parentLot);
~MissionOfferComponent() override;

View File

@@ -10,7 +10,7 @@ ModelComponent::ModelComponent(Entity* parent) : Component(parent) {
void ModelComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
// ItemComponent Serialization. Pets do not get this serialization.
if (!m_Parent->HasComponent(COMPONENT_TYPE_PET)) {
if (!m_Parent->HasComponent(eReplicaComponentType::PET)) {
outBitStream->Write1();
outBitStream->Write<LWOOBJID>(m_userModelID != LWOOBJID_EMPTY ? m_userModelID : m_Parent->GetObjectID());
outBitStream->Write<int>(0);

View File

@@ -4,6 +4,7 @@
#include "NiPoint3.h"
#include "NiQuaternion.h"
#include "Component.h"
#include "eReplicaComponentType.h"
class Entity;
@@ -12,7 +13,7 @@ class Entity;
*/
class ModelComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_MODEL;
static const eReplicaComponentType ComponentType = eReplicaComponentType::MODEL;
ModelComponent(Entity* parent);

View File

@@ -3,6 +3,7 @@
#include "BitStream.h"
#include "Entity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* Component that belongs to an object that may be modularly built, like cars and rockets. Note that this is not the
@@ -11,7 +12,7 @@
*/
class ModuleAssemblyComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_MODULE_ASSEMBLY;
static const eReplicaComponentType ComponentType = eReplicaComponentType::MODULE_ASSEMBLY;
ModuleAssemblyComponent(Entity* MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION);
~ModuleAssemblyComponent() override;

View File

@@ -10,6 +10,10 @@
#include "EntityManager.h"
#include "SimplePhysicsComponent.h"
#include "dZoneManager.h"
#include "CDClientManager.h"
#include "CDComponentsRegistryTable.h"
#include "CDPhysicsComponentTable.h"
std::map<LOT, float> MovementAIComponent::m_PhysicsSpeedCache = {};
@@ -19,7 +23,7 @@ MovementAIComponent::MovementAIComponent(Entity* parent, MovementAIInfo info) :
m_BaseCombatAI = nullptr;
m_BaseCombatAI = reinterpret_cast<BaseCombatAIComponent*>(m_Parent->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI));
m_BaseCombatAI = reinterpret_cast<BaseCombatAIComponent*>(m_Parent->GetComponent(eReplicaComponentType::BASE_COMBAT_AI));
//Try and fix the insane values:
if (m_Info.wanderRadius > 5.0f) m_Info.wanderRadius = m_Info.wanderRadius * 0.5f;
@@ -132,7 +136,6 @@ void MovementAIComponent::Update(const float deltaTime) {
} else if (m_CurrentPath->pathWaypoints.size() > m_WaypointPathIndex) ArrivedAtPathWaypoint();
}
}
}
// if (m_HaltDistance > 0) {
@@ -421,13 +424,13 @@ float MovementAIComponent::GetBaseSpeed(LOT lot) {
return it->second;
}
CDComponentsRegistryTable* componentRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
CDPhysicsComponentTable* physicsComponentTable = CDClientManager::Instance()->GetTable<CDPhysicsComponentTable>("PhysicsComponent");
CDComponentsRegistryTable* componentRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
CDPhysicsComponentTable* physicsComponentTable = CDClientManager::Instance().GetTable<CDPhysicsComponentTable>();
int32_t componentID;
CDPhysicsComponent* physicsComponent = nullptr;
componentID = componentRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_CONTROLLABLE_PHYSICS, -1);
componentID = componentRegistryTable->GetByIDAndType(lot, eReplicaComponentType::CONTROLLABLE_PHYSICS, -1);
if (componentID != -1) {
physicsComponent = physicsComponentTable->GetByID(componentID);
@@ -435,7 +438,7 @@ float MovementAIComponent::GetBaseSpeed(LOT lot) {
goto foundComponent;
}
componentID = componentRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_SIMPLE_PHYSICS, -1);
componentID = componentRegistryTable->GetByIDAndType(lot, eReplicaComponentType::SIMPLE_PHYSICS, -1);
if (componentID != -1) {
physicsComponent = physicsComponentTable->GetByID(componentID);

View File

@@ -13,6 +13,7 @@
#include "Game.h"
#include "dLogger.h"
#include "Component.h"
#include "eReplicaComponentType.h"
#include <vector>
class ControllablePhysicsComponent;
@@ -56,7 +57,7 @@ struct MovementAIInfo {
*/
class MovementAIComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_MOVEMENT_AI;
static const eReplicaComponentType ComponentType = eReplicaComponentType::MOVEMENT_AI;
MovementAIComponent(Entity* parentEntity, MovementAIInfo info);
~MovementAIComponent() override;

View File

@@ -12,11 +12,12 @@
#include "GameMessages.h"
#include "CppScripts.h"
#include "SimplePhysicsComponent.h"
#include "Zone.h"
MoverSubComponent::MoverSubComponent(const NiPoint3& startPos) {
mPosition = {};
mState = MovementPlatformState::Stopped;
mState = eMovementPlatformState::Stopped;
mDesiredWaypointIndex = 0; // -1;
mInReverse = false;
mShouldStopAtDesiredWaypoint = false;
@@ -127,7 +128,7 @@ void MovingPlatformComponent::OnCompleteRebuild() {
StartPathing();
}
void MovingPlatformComponent::SetMovementState(MovementPlatformState value) {
void MovingPlatformComponent::SetMovementState(eMovementPlatformState value) {
auto* subComponent = static_cast<MoverSubComponent*>(m_MoverSubComponent);
subComponent->mState = value;
@@ -152,7 +153,7 @@ void MovingPlatformComponent::StartPathing() {
auto* subComponent = static_cast<MoverSubComponent*>(m_MoverSubComponent);
subComponent->mShouldStopAtDesiredWaypoint = true;
subComponent->mState = MovementPlatformState::Stationary;
subComponent->mState = eMovementPlatformState::Stationary;
NiPoint3 targetPosition;
@@ -174,7 +175,7 @@ void MovingPlatformComponent::StartPathing() {
}
m_Parent->AddCallbackTimer(subComponent->mWaitTime, [this] {
SetMovementState(MovementPlatformState::Moving);
SetMovementState(eMovementPlatformState::Moving);
});
const auto travelTime = Vector3::Distance(targetPosition, subComponent->mPosition) / subComponent->mSpeed + 1.5f;
@@ -199,7 +200,7 @@ void MovingPlatformComponent::StartPathing() {
void MovingPlatformComponent::ContinuePathing() {
auto* subComponent = static_cast<MoverSubComponent*>(m_MoverSubComponent);
subComponent->mState = MovementPlatformState::Stationary;
subComponent->mState = eMovementPlatformState::Stationary;
subComponent->mCurrentWaypointIndex = subComponent->mNextWaypointIndex;
@@ -282,7 +283,7 @@ void MovingPlatformComponent::ContinuePathing() {
m_Parent->CancelCallbackTimers();
m_Parent->AddCallbackTimer(subComponent->mWaitTime, [this] {
SetMovementState(MovementPlatformState::Moving);
SetMovementState(eMovementPlatformState::Moving);
});
auto travelTime = Vector3::Distance(targetPosition, subComponent->mPosition) / subComponent->mSpeed + 1.5;
@@ -313,7 +314,7 @@ void MovingPlatformComponent::StopPathing() {
m_PathingStopped = true;
subComponent->mState = MovementPlatformState::Stopped;
subComponent->mState = eMovementPlatformState::Stopped;
subComponent->mDesiredWaypointIndex = -1;
subComponent->mShouldStopAtDesiredWaypoint = false;

View File

@@ -13,6 +13,10 @@
#include "dCommonVars.h"
#include "EntityManager.h"
#include "Component.h"
#include "eMovementPlatformState.h"
#include "eReplicaComponentType.h"
class Path;
/**
* Different types of available platforms
@@ -26,16 +30,6 @@ enum class eMoverSubComponentType : uint32_t {
simpleMover = 5,
};
/**
* The different types of platform movement state, supposedly a bitmap
*/
enum class MovementPlatformState : uint32_t
{
Moving = 0b00010,
Stationary = 0b11001,
Stopped = 0b01100
};
/**
* Sub component for moving platforms that determine the actual current movement state
*/
@@ -49,7 +43,7 @@ public:
/**
* The state the platform is currently in
*/
MovementPlatformState mState = MovementPlatformState::Stationary;
eMovementPlatformState mState = eMovementPlatformState::Stationary;
/**
* The waypoint this platform currently wants to traverse to
@@ -112,7 +106,7 @@ public:
*/
class MovingPlatformComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_MOVING_PLATFORM;
static const eReplicaComponentType ComponentType = eReplicaComponentType::MOVING_PLATFORM;
MovingPlatformComponent(Entity* parent, const std::string& pathName);
~MovingPlatformComponent() override;
@@ -133,7 +127,7 @@ public:
* Updates the movement state for the moving platform
* @param value the movement state to set
*/
void SetMovementState(MovementPlatformState value);
void SetMovementState(eMovementPlatformState value);
/**
* Instructs the moving platform to go to some waypoint

View File

@@ -20,6 +20,9 @@
#include "dConfig.h"
#include "dChatFilter.h"
#include "Database.h"
#include "EntityInfo.h"
#include "eMissionTaskType.h"
#include "eGameMasterLevel.h"
std::unordered_map<LOT, PetComponent::PetPuzzleData> PetComponent::buildCache{};
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::currentActivities{};
@@ -59,7 +62,7 @@ std::map<LOT, uint32_t> PetComponent::petFlags = {
{ 13067, 838 }, // Skeleton dragon
};
PetComponent::PetComponent(Entity* parent, uint32_t componentId) : Component(parent) {
PetComponent::PetComponent(Entity* parent, uint32_t componentId): Component(parent) {
m_ComponentId = componentId;
m_Interaction = LWOOBJID_EMPTY;
@@ -118,21 +121,23 @@ void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpd
outBitStream->Write(m_Owner);
}
outBitStream->Write(tamed);
if (tamed) {
outBitStream->Write(m_ModerationStatus);
if (bIsInitialUpdate) {
outBitStream->Write(tamed);
if (tamed) {
outBitStream->Write(m_ModerationStatus);
const auto nameData = GeneralUtils::UTF8ToUTF16(m_Name);
const auto ownerNameData = GeneralUtils::UTF8ToUTF16(m_OwnerName);
const auto nameData = GeneralUtils::UTF8ToUTF16(m_Name);
const auto ownerNameData = GeneralUtils::UTF8ToUTF16(m_OwnerName);
outBitStream->Write(static_cast<uint8_t>(nameData.size()));
for (const auto c : nameData) {
outBitStream->Write(c);
}
outBitStream->Write(static_cast<uint8_t>(nameData.size()));
for (const auto c : nameData) {
outBitStream->Write(c);
}
outBitStream->Write(static_cast<uint8_t>(ownerNameData.size()));
for (const auto c : ownerNameData) {
outBitStream->Write(c);
outBitStream->Write(static_cast<uint8_t>(ownerNameData.size()));
for (const auto c : ownerNameData) {
outBitStream->Write(c);
}
}
}
}
@@ -599,7 +604,7 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) {
auto* missionComponent = tamer->GetComponent<MissionComponent>();
if (missionComponent != nullptr) {
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_PET_TAMING, m_Parent->GetLOT());
missionComponent->Progress(eMissionTaskType::PET_TAMING, m_Parent->GetLOT());
}
SetStatus(1);
@@ -916,16 +921,16 @@ void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) {
return;
}
// If we are out of imagination despawn the pet.
if (playerDestroyableComponent->GetImagination() == 0) {
this->Deactivate();
auto playerEntity = playerDestroyableComponent->GetParent();
if (!playerEntity) return;
// If we are out of imagination despawn the pet.
if (playerDestroyableComponent->GetImagination() == 0) {
this->Deactivate();
auto playerEntity = playerDestroyableComponent->GetParent();
if (!playerEntity) return;
GameMessages::SendUseItemRequirementsResponse(playerEntity->GetObjectID(), playerEntity->GetSystemAddress(), UseItemResponse::NoImaginationForPet);
}
GameMessages::SendUseItemRequirementsResponse(playerEntity->GetObjectID(), playerEntity->GetSystemAddress(), UseItemResponse::NoImaginationForPet);
}
this->AddDrainImaginationTimer(item);
this->AddDrainImaginationTimer(item);
});
}
@@ -983,7 +988,7 @@ void PetComponent::Command(NiPoint3 position, LWOOBJID source, int32_t commandTy
// TODO: Go to player
}
if (owner->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) {
if (owner->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
ChatPackets::SendSystemMessage(owner->GetSystemAddress(), u"Commmand Type: " + (GeneralUtils::to_u16string(commandType)) + u" - Type Id: " + (GeneralUtils::to_u16string(typeId)));
}
}
@@ -1075,7 +1080,7 @@ void PetComponent::SetPetNameForModeration(const std::string& petName) {
int approved = 1; //default, in mod
//Make sure that the name isn't already auto-approved:
if (Game::chatFilter->IsSentenceOkay(petName, 0).empty()) {
if (Game::chatFilter->IsSentenceOkay(petName, eGameMasterLevel::CIVILIAN).empty()) {
approved = 2; //approved
}

View File

@@ -4,6 +4,7 @@
#include "MovementAIComponent.h"
#include "Component.h"
#include "Preconditions.h"
#include "eReplicaComponentType.h"
enum class PetAbilityType
{
@@ -20,7 +21,7 @@ enum class PetAbilityType
class PetComponent : public Component
{
public:
static const uint32_t ComponentType = COMPONENT_TYPE_PET;
static const eReplicaComponentType ComponentType = eReplicaComponentType::PET;
explicit PetComponent(Entity* parentEntity, uint32_t componentId);
~PetComponent() override;

View File

@@ -14,11 +14,13 @@
#include "EntityManager.h"
#include "ControllablePhysicsComponent.h"
#include "GameMessages.h"
#include "ePhysicsEffectType.h"
#include "CDClientManager.h"
#include "CDComponentsRegistryTable.h"
#include "CDPhysicsComponentTable.h"
#include "dServer.h"
#include "EntityInfo.h"
#include "dpWorld.h"
#include "dpEntity.h"
@@ -35,7 +37,7 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : Component(par
m_PositionInfoDirty = false;
m_IsPhysicsEffectActive = false;
m_EffectType = 0;
m_EffectType = ePhysicsEffectType::PUSH;
m_DirectionalMultiplier = 0.0f;
m_MinMax = false;
@@ -142,10 +144,10 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : Component(par
*/
if (!m_HasCreatedPhysics) {
CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), COMPONENT_TYPE_PHANTOM_PHYSICS);
CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::PHANTOM_PHYSICS);
CDPhysicsComponentTable* physComp = CDClientManager::Instance()->GetTable<CDPhysicsComponentTable>("PhysicsComponent");
CDPhysicsComponentTable* physComp = CDClientManager::Instance().GetTable<CDPhysicsComponentTable>();
if (physComp == nullptr) return;
@@ -252,10 +254,10 @@ void PhantomPhysicsComponent::CreatePhysics() {
y = m_Parent->GetVar<float>(u"primitiveModelValueY");
z = m_Parent->GetVar<float>(u"primitiveModelValueZ");
} else {
CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), COMPONENT_TYPE_PHANTOM_PHYSICS);
CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::PHANTOM_PHYSICS);
CDPhysicsComponentTable* physComp = CDClientManager::Instance()->GetTable<CDPhysicsComponentTable>("PhysicsComponent");
CDPhysicsComponentTable* physComp = CDClientManager::Instance().GetTable<CDPhysicsComponentTable>();
if (physComp == nullptr) return;
@@ -404,7 +406,7 @@ void PhantomPhysicsComponent::SetDirectionalMultiplier(float mul) {
m_EffectInfoDirty = true;
}
void PhantomPhysicsComponent::SetEffectType(uint32_t type) {
void PhantomPhysicsComponent::SetEffectType(ePhysicsEffectType type) {
m_EffectType = type;
m_EffectInfoDirty = true;
}

View File

@@ -12,10 +12,12 @@
#include "CppScripts.h"
#include "InvalidScript.h"
#include "Component.h"
#include "eReplicaComponentType.h"
class LDFBaseData;
class Entity;
class dpEntity;
enum class ePhysicsEffectType : uint32_t ;
/**
* Allows the creation of phantom physics for an entity: a physics object that is generally invisible but can be
@@ -25,7 +27,7 @@ class dpEntity;
*/
class PhantomPhysicsComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_PHANTOM_PHYSICS;
static const eReplicaComponentType ComponentType = eReplicaComponentType::PHANTOM_PHYSICS;
PhantomPhysicsComponent(Entity* parent);
~PhantomPhysicsComponent() override;
@@ -102,13 +104,13 @@ public:
* Returns the effect that's currently active, defaults to 0
* @return the effect that's currently active
*/
uint32_t GetEffectType() const { return m_EffectType; }
ePhysicsEffectType GetEffectType() const { return m_EffectType; }
/**
* Sets the effect that's currently active
* @param type the effect to set
*/
void SetEffectType(uint32_t type);
void SetEffectType(ePhysicsEffectType type);
/**
* Returns the Physics entity for the component
@@ -167,7 +169,7 @@ private:
/**
* The physics effect that's currently active, defaults to 0
*/
uint32_t m_EffectType;
ePhysicsEffectType m_EffectType;
/**
* A scaling multiplier to add to the directional vector

View File

@@ -7,8 +7,8 @@ PlayerForcedMovementComponent::PlayerForcedMovementComponent(Entity* parent) : C
PlayerForcedMovementComponent::~PlayerForcedMovementComponent() {}
void PlayerForcedMovementComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
outBitStream->Write(m_DirtyInfo);
if (m_DirtyInfo) {
outBitStream->Write(m_DirtyInfo || bIsInitialUpdate);
if (m_DirtyInfo || bIsInitialUpdate) {
outBitStream->Write(m_PlayerOnRail);
outBitStream->Write(m_ShowBillboard);
}

View File

@@ -2,6 +2,7 @@
#include "Entity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* Component that handles player forced movement
@@ -9,7 +10,7 @@
*/
class PlayerForcedMovementComponent : public Component {
public:
static const uint32_t ComponentType = eReplicaComponentType::COMPONENT_TYPE_PLAYER_FORCED_MOVEMENT;
static const eReplicaComponentType ComponentType = eReplicaComponentType::PLAYER_FORCED_MOVEMENT;
/**
* Constructor for this component

View File

@@ -34,8 +34,8 @@ void PossessableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn
outBitStream->Write(m_Possessor != LWOOBJID_EMPTY);
if (m_Possessor != LWOOBJID_EMPTY) outBitStream->Write(m_Possessor);
outBitStream->Write(m_AnimationFlag != eAnimationFlags::IDLE_INVALID);
if (m_AnimationFlag != eAnimationFlags::IDLE_INVALID) outBitStream->Write(m_AnimationFlag);
outBitStream->Write(m_AnimationFlag != eAnimationFlags::IDLE_NONE);
if (m_AnimationFlag != eAnimationFlags::IDLE_NONE) outBitStream->Write(m_AnimationFlag);
outBitStream->Write(m_ImmediatelyDepossess);
m_ImmediatelyDepossess = false; // reset flag

View File

@@ -6,6 +6,7 @@
#include "Item.h"
#include "PossessorComponent.h"
#include "eAninmationFlags.h"
#include "eReplicaComponentType.h"
/**
* Represents an entity that can be controlled by some other entity, generally used by cars to indicate that some
@@ -13,7 +14,7 @@
*/
class PossessableComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_POSSESSABLE;
static const eReplicaComponentType ComponentType = eReplicaComponentType::POSSESSABLE;
PossessableComponent(Entity* parentEntity, uint32_t componentId);
@@ -109,7 +110,7 @@ private:
* @brief What animaiton flag to use
*
*/
eAnimationFlags m_AnimationFlag = eAnimationFlags::IDLE_INVALID;
eAnimationFlags m_AnimationFlag = eAnimationFlags::IDLE_NONE;
/**
* @brief Should this be immediately depossessed

View File

@@ -54,7 +54,7 @@ void PossessorComponent::Mount(Entity* mount) {
// GM's to send
GameMessages::SendSetJetPackMode(m_Parent, false);
GameMessages::SendVehicleUnlockInput(mount->GetObjectID(), false, m_Parent->GetSystemAddress());
GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStunState::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStateChangeType::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
EntityManager::Instance()->SerializeEntity(m_Parent);
EntityManager::Instance()->SerializeEntity(mount);

View File

@@ -3,6 +3,7 @@
#include "BitStream.h"
#include "Entity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
// possession types
enum class ePossessionType : uint8_t {
@@ -17,7 +18,7 @@ enum class ePossessionType : uint8_t {
*/
class PossessorComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_POSSESSOR;
static const eReplicaComponentType ComponentType = eReplicaComponentType::POSSESSOR;
PossessorComponent(Entity* parent);
~PossessorComponent() override;

View File

@@ -9,6 +9,7 @@
#include "BitStream.h"
#include "Entity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
struct PropertyState {
LWOOBJID ownerID;
@@ -21,7 +22,7 @@ struct PropertyState {
*/
class PropertyComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_PROPERTY;
static const eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY;
explicit PropertyComponent(Entity* parentEntity);
~PropertyComponent() override;
[[nodiscard]] PropertyState* GetPropertyState() const { return m_PropertyState; };

View File

@@ -11,11 +11,13 @@
#include "CharacterComponent.h"
#include "UserManager.h"
#include "dLogger.h"
#include "AMFFormat.h"
#include "eGameMasterLevel.h"
PropertyEntranceComponent::PropertyEntranceComponent(uint32_t componentID, Entity* parent) : Component(parent) {
this->propertyQueries = {};
auto table = CDClientManager::Instance()->GetTable<CDPropertyEntranceComponentTable>("PropertyEntranceComponent");
auto table = CDClientManager::Instance().GetTable<CDPropertyEntranceComponentTable>();
const auto& entry = table->GetByID(componentID);
this->m_MapID = entry.mapID;
@@ -270,7 +272,7 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl
bool isModeratorApproved = propertyEntry->getBoolean(10);
if (!isModeratorApproved && entity->GetGMLevel() >= GAME_MASTER_LEVEL_LEAD_MODERATOR) {
if (!isModeratorApproved && entity->GetGMLevel() >= eGameMasterLevel::LEAD_MODERATOR) {
propertyName = "[AWAITING APPROVAL]";
propertyDescription = "[AWAITING APPROVAL]";
isModeratorApproved = true;

View File

@@ -6,13 +6,14 @@
#include "Entity.h"
#include "EntityManager.h"
#include "GameMessages.h"
#include "eReplicaComponentType.h"
/**
* Represents the launch pad that's used to select and browse properties
*/
class PropertyEntranceComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_PROPERTY_ENTRANCE;
static const eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY_ENTRANCE;
explicit PropertyEntranceComponent(uint32_t componentID, Entity* parent);
/**

View File

@@ -17,6 +17,8 @@
#include "Player.h"
#include "RocketLaunchpadControlComponent.h"
#include "PropertyEntranceComponent.h"
#include "InventoryComponent.h"
#include "eMissionTaskType.h"
#include <vector>
#include "CppScripts.h"
@@ -200,6 +202,16 @@ bool PropertyManagementComponent::Claim(const LWOOBJID playerId) {
// If we are not on our clone do not allow us to claim the property
if (propertyCloneId != playerCloneId) return false;
std::string name = zone->GetZoneName();
std::string description = "";
auto prop_path = zone->GetPath(m_Parent->GetVarAsString(u"propertyName"));
if (prop_path){
if (!prop_path->property.displayName.empty()) name = prop_path->property.displayName;
description = prop_path->property.displayDesc;
}
SetOwnerId(playerId);
propertyId = ObjectIDManager::GenerateRandomObjectID();
@@ -207,14 +219,15 @@ bool PropertyManagementComponent::Claim(const LWOOBJID playerId) {
auto* insertion = Database::CreatePreppedStmt(
"INSERT INTO properties"
"(id, owner_id, template_id, clone_id, name, description, rent_amount, rent_due, privacy_option, last_updated, time_claimed, rejection_reason, reputation, zone_id, performance_cost)"
"VALUES (?, ?, ?, ?, ?, '', 0, 0, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '', 0, ?, 0.0)"
"VALUES (?, ?, ?, ?, ?, ?, 0, 0, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '', 0, ?, 0.0)"
);
insertion->setUInt64(1, propertyId);
insertion->setUInt64(2, (uint32_t)playerId);
insertion->setUInt(3, templateId);
insertion->setUInt64(4, playerCloneId);
insertion->setString(5, zone->GetZoneName().c_str());
insertion->setInt(6, propertyZoneId);
insertion->setString(5, name.c_str());
insertion->setString(6, description.c_str());
insertion->setInt(7, propertyZoneId);
// Try and execute the query, print an error if it fails.
try {
@@ -242,7 +255,7 @@ void PropertyManagementComponent::OnStartBuilding() {
LWOMAPID zoneId = 1100;
const auto entrance = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_PROPERTY_ENTRANCE);
const auto entrance = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::PROPERTY_ENTRANCE);
originalPrivacyOption = privacyOption;
@@ -392,7 +405,7 @@ void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const N
});
// Progress place model missions
auto missionComponent = entity->GetComponent<MissionComponent>();
if (missionComponent != nullptr) missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_PLACE_MODEL, 0);
if (missionComponent != nullptr) missionComponent->Progress(eMissionTaskType::PLACE_MODEL, 0);
}
void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int deleteReason) {
@@ -463,7 +476,7 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet
settings.push_back(propertyObjectID);
settings.push_back(modelType);
inventoryComponent->AddItem(6662, 1, eLootSourceType::LOOT_SOURCE_DELETION, eInventoryType::HIDDEN, settings, LWOOBJID_EMPTY, false, false, spawnerId);
inventoryComponent->AddItem(6662, 1, eLootSourceType::LOOT_SOURCE_DELETION, eInventoryType::MODELS_IN_BBB, settings, LWOOBJID_EMPTY, false, false, spawnerId);
auto* item = inventoryComponent->FindItemBySubKey(spawnerId);
if (item == nullptr) {
@@ -706,7 +719,7 @@ void PropertyManagementComponent::Save() {
insertion->setDouble(9, rotation.y);
insertion->setDouble(10, rotation.z);
insertion->setDouble(11, rotation.w);
insertion->setString(12, "Objects_" + std::to_string(entity->GetLOT()) + "_name"); // Model name. TODO make this customizable
insertion->setString(12, ("Objects_" + std::to_string(entity->GetLOT()) + "_name").c_str()); // Model name. TODO make this customizable
insertion->setString(13, ""); // Model description. TODO implement this.
insertion->setDouble(14, 0); // behavior 1. TODO implement this.
insertion->setDouble(15, 0); // behavior 2. TODO implement this.

View File

@@ -3,6 +3,7 @@
#include <chrono>
#include "Entity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* Information regarding which players may visit this property
@@ -31,7 +32,7 @@ enum class PropertyPrivacyOption
class PropertyManagementComponent : public Component
{
public:
static const uint32_t ComponentType = COMPONENT_TYPE_PROPERTY_MANAGEMENT;
static const eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY_MANAGEMENT;
PropertyManagementComponent(Entity* parent);
static PropertyManagementComponent* Instance();

View File

@@ -2,6 +2,7 @@
#include "Entity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* The property guard that stands on a property before it's claimed, allows entities to attempt claiming this property.
@@ -9,7 +10,7 @@
class PropertyVendorComponent : public Component
{
public:
static const uint32_t ComponentType = COMPONENT_TYPE_PROPERTY_VENDOR;
static const eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY_VENDOR;
explicit PropertyVendorComponent(Entity* parent);
/**

View File

@@ -11,6 +11,7 @@
#include "dpWorld.h"
#include "dpEntity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* Utility component for detecting how close entities are to named proximities for this entity. Allows you to store
@@ -18,7 +19,7 @@
*/
class ProximityMonitorComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_PROXIMITY_MONITOR;
static const eReplicaComponentType ComponentType = eReplicaComponentType::PROXIMITY_MONITOR;
ProximityMonitorComponent(Entity* parentEntity, int smallRadius = -1, int largeRadius = -1);
~ProximityMonitorComponent() override;

View File

@@ -15,12 +15,14 @@
#include "Player.h"
#include "PossessableComponent.h"
#include "PossessorComponent.h"
#include "RacingTaskParam.h"
#include "eRacingTaskParam.h"
#include "Spawner.h"
#include "VehiclePhysicsComponent.h"
#include "dServer.h"
#include "dZoneManager.h"
#include "dConfig.h"
#include "Loot.h"
#include "eMissionTaskType.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288
@@ -98,7 +100,7 @@ void RacingControlComponent::OnPlayerLoaded(Entity* player) {
}
void RacingControlComponent::LoadPlayerVehicle(Entity* player,
bool initialLoad) {
uint32_t positionNumber, bool initialLoad) {
// Load the player's vehicle.
if (player == nullptr) {
@@ -126,33 +128,18 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
auto* path = dZoneManager::Instance()->GetZone()->GetPath(
GeneralUtils::UTF16ToWTF8(m_PathName));
auto startPosition = path->pathWaypoints[0].position + NiPoint3::UNIT_Y * 3;
const auto spacing = 15;
// This sometimes spawns the vehicle out of the map if there are lots of
// players loaded.
const auto range = m_LoadedPlayers * spacing;
startPosition =
startPosition + NiPoint3::UNIT_Z * ((m_LeadingPlayer / 2) +
m_RacingPlayers.size() * spacing);
auto startRotation =
NiQuaternion::LookAt(startPosition, startPosition + NiPoint3::UNIT_X);
auto angles = startRotation.GetEulerAngles();
angles.y -= M_PI;
startRotation = NiQuaternion::FromEulerAngles(angles);
Game::logger->Log("RacingControlComponent",
"Start position <%f, %f, %f>, <%f, %f, %f>",
startPosition.x, startPosition.y, startPosition.z,
angles.x * (180.0f / M_PI), angles.y * (180.0f / M_PI),
angles.z * (180.0f / M_PI));
auto spawnPointEntities = EntityManager::Instance()->GetEntitiesByLOT(4843);
auto startPosition = NiPoint3::ZERO;
auto startRotation = NiQuaternion::IDENTITY;
const std::string placementAsString = std::to_string(positionNumber);
for (auto entity : spawnPointEntities) {
if (!entity) continue;
if (entity->GetVarAsString(u"placement") == placementAsString) {
startPosition = entity->GetPosition();
startRotation = entity->GetRotation();
break;
}
}
// Make sure the player is at the correct position.
@@ -319,30 +306,58 @@ void RacingControlComponent::OnRequestDie(Entity* player) {
auto* vehicle =
EntityManager::Instance()->GetEntity(racingPlayer.vehicleID);
if (vehicle == nullptr) {
return;
}
if (!vehicle) return;
if (!racingPlayer.noSmashOnReload) {
racingPlayer.smashedTimes++;
GameMessages::SendDie(vehicle, vehicle->GetObjectID(), LWOOBJID_EMPTY, true,
VIOLENT, u"", 0, 0, 90.0f, false, true, 0);
auto* destroyableComponent = vehicle->GetComponent<DestroyableComponent>();
uint32_t respawnImagination = 0;
// Reset imagination to half its current value, rounded up to the nearest value divisible by 10, as it was done in live.
// Do not actually change the value yet. Do that on respawn.
if (destroyableComponent) {
respawnImagination = static_cast<int32_t>(ceil(destroyableComponent->GetImagination() / 2.0f / 10.0f)) * 10.0f;
GameMessages::SendSetResurrectRestoreValues(vehicle, -1, -1, respawnImagination);
}
// Respawn the player in 2 seconds, as was done in live. Not sure if this value is in a setting somewhere else...
vehicle->AddCallbackTimer(2.0f, [=]() {
if (!vehicle || !this->m_Parent) return;
GameMessages::SendRacingResetPlayerToLastReset(
m_Parent->GetObjectID(), racingPlayer.playerID,
UNASSIGNED_SYSTEM_ADDRESS);
GameMessages::SendVehicleStopBoost(vehicle, player->GetSystemAddress(), true);
GameMessages::SendRacingSetPlayerResetInfo(
m_Parent->GetObjectID(), racingPlayer.lap,
racingPlayer.respawnIndex, player->GetObjectID(),
racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1,
UNASSIGNED_SYSTEM_ADDRESS);
GameMessages::SendResurrect(vehicle);
auto* destroyableComponent = vehicle->GetComponent<DestroyableComponent>();
// Reset imagination to half its current value, rounded up to the nearest value divisible by 10, as it was done in live.
if (destroyableComponent) destroyableComponent->SetImagination(respawnImagination);
EntityManager::Instance()->SerializeEntity(vehicle);
});
auto* characterComponent = player->GetComponent<CharacterComponent>();
if (characterComponent != nullptr) {
characterComponent->UpdatePlayerStatistic(RacingTimesWrecked);
}
} else {
GameMessages::SendRacingSetPlayerResetInfo(
m_Parent->GetObjectID(), racingPlayer.lap,
racingPlayer.respawnIndex, player->GetObjectID(),
racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1,
UNASSIGNED_SYSTEM_ADDRESS);
GameMessages::SendRacingResetPlayerToLastReset(
m_Parent->GetObjectID(), racingPlayer.playerID,
UNASSIGNED_SYSTEM_ADDRESS);
}
// Reset player to last checkpoint
GameMessages::SendRacingSetPlayerResetInfo(
m_Parent->GetObjectID(), racingPlayer.lap,
racingPlayer.respawnIndex, player->GetObjectID(),
racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1,
UNASSIGNED_SYSTEM_ADDRESS);
GameMessages::SendRacingResetPlayerToLastReset(
m_Parent->GetObjectID(), racingPlayer.playerID,
UNASSIGNED_SYSTEM_ADDRESS);
auto* characterComponent = player->GetComponent<CharacterComponent>();
if (characterComponent != nullptr) {
characterComponent->UpdatePlayerStatistic(RacingTimesWrecked);
}
return;
}
}
@@ -361,19 +376,6 @@ void RacingControlComponent::OnRacingPlayerInfoResetFinished(Entity* player) {
return;
}
if (!racingPlayer.noSmashOnReload) {
GameMessages::SendDie(vehicle, LWOOBJID_EMPTY, LWOOBJID_EMPTY, true,
VIOLENT, u"", 0, 0, 0, true, false, 0);
GameMessages::SendVehicleUnlockInput(racingPlayer.vehicleID, false,
UNASSIGNED_SYSTEM_ADDRESS);
GameMessages::SendVehicleSetWheelLockState(
racingPlayer.vehicleID, false, false,
UNASSIGNED_SYSTEM_ADDRESS);
GameMessages::SendResurrect(vehicle);
}
racingPlayer.noSmashOnReload = false;
return;
@@ -409,18 +411,18 @@ void RacingControlComponent::HandleMessageBoxResponse(Entity* player,
if (missionComponent == nullptr) return;
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, 0, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_COMPETED_IN_RACE); // Progress task for competing in a race
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, data->smashedTimes, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_SAFE_DRIVER); // Finish a race without being smashed.
missionComponent->Progress(eMissionTaskType::RACING, 0, (LWOOBJID)eRacingTaskParam::COMPETED_IN_RACE); // Progress task for competing in a race
missionComponent->Progress(eMissionTaskType::RACING, data->smashedTimes, (LWOOBJID)eRacingTaskParam::SAFE_DRIVER); // Finish a race without being smashed.
// If solo racing is enabled OR if there are 3 players in the race, progress placement tasks.
if (m_SoloRacing || m_LoadedPlayers > 2) {
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, data->finished, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_FINISH_WITH_PLACEMENT); // Finish in 1st place on a race
missionComponent->Progress(eMissionTaskType::RACING, data->finished, (LWOOBJID)eRacingTaskParam::FINISH_WITH_PLACEMENT); // Finish in 1st place on a race
if (data->finished == 1) {
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_FIRST_PLACE_MULTIPLE_TRACKS); // Finish in 1st place on multiple tracks.
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_WIN_RACE_IN_WORLD); // Finished first place in specific world.
missionComponent->Progress(eMissionTaskType::RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::FIRST_PLACE_MULTIPLE_TRACKS); // Finish in 1st place on multiple tracks.
missionComponent->Progress(eMissionTaskType::RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::WIN_RACE_IN_WORLD); // Finished first place in specific world.
}
if (data->finished == m_LoadedPlayers) {
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_LAST_PLACE_FINISH); // Finished first place in specific world.
missionComponent->Progress(eMissionTaskType::RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::LAST_PLACE_FINISH); // Finished first place in specific world.
}
}
} else if (id == "ACT_RACE_EXIT_THE_RACE?" || id == "Exit") {
@@ -567,12 +569,12 @@ void RacingControlComponent::Update(float deltaTime) {
Game::logger->Log("RacingControlComponent",
"Loading all players...");
for (size_t i = 0; i < m_LobbyPlayers.size(); i++) {
for (size_t positionNumber = 0; positionNumber < m_LobbyPlayers.size(); positionNumber++) {
Game::logger->Log("RacingControlComponent",
"Loading player now!");
auto* player =
EntityManager::Instance()->GetEntity(m_LobbyPlayers[i]);
EntityManager::Instance()->GetEntity(m_LobbyPlayers[positionNumber]);
if (player == nullptr) {
return;
@@ -581,7 +583,7 @@ void RacingControlComponent::Update(float deltaTime) {
Game::logger->Log("RacingControlComponent",
"Loading player now NOW!");
LoadPlayerVehicle(player, true);
LoadPlayerVehicle(player, positionNumber + 1, true);
m_Loaded = true;
}
@@ -842,7 +844,7 @@ void RacingControlComponent::Update(float deltaTime) {
if (missionComponent != nullptr) {
// Progress lap time tasks
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, (lapTime) * 1000, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_LAP_TIME);
missionComponent->Progress(eMissionTaskType::RACING, (lapTime) * 1000, (LWOOBJID)eRacingTaskParam::LAP_TIME);
if (player.lap == 3) {
m_Finished++;
@@ -858,7 +860,7 @@ void RacingControlComponent::Update(float deltaTime) {
raceTime, raceTime * 1000);
// Entire race time
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, (raceTime) * 1000, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_TOTAL_TRACK_TIME);
missionComponent->Progress(eMissionTaskType::RACING, (raceTime) * 1000, (LWOOBJID)eRacingTaskParam::TOTAL_TRACK_TIME);
auto* characterComponent = playerEntity->GetComponent<CharacterComponent>();
if (characterComponent != nullptr) {

View File

@@ -7,6 +7,7 @@
#include "BitStream.h"
#include "Entity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* Information for each player in the race
@@ -104,7 +105,7 @@ struct RacingPlayerInfo {
*/
class RacingControlComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_RACING_CONTROL;
static const eReplicaComponentType ComponentType = eReplicaComponentType::RACING_CONTROL;
RacingControlComponent(Entity* parentEntity);
~RacingControlComponent();
@@ -123,7 +124,7 @@ public:
* @param player The player who's vehicle to initialize.
* @param initialLoad Is this the first time the player is loading in this race?
*/
void LoadPlayerVehicle(Entity* player, bool initialLoad = false);
void LoadPlayerVehicle(Entity* player, uint32_t positionNumber, bool initialLoad = false);
/**
* Invoked when the client says it has loaded in.

View File

@@ -10,8 +10,7 @@
RailActivatorComponent::RailActivatorComponent(Entity* parent, int32_t componentID) : Component(parent) {
m_ComponentID = componentID;
const auto tableData = CDClientManager::Instance()
->GetTable<CDRailActivatorComponentTable>("RailActivatorComponent")->GetEntryByID(componentID);
const auto tableData = CDClientManager::Instance().GetTable<CDRailActivatorComponentTable>()->GetEntryByID(componentID);;
m_Path = parent->GetVar<std::u16string>(u"rail_path");
m_PathDirection = parent->GetVar<bool>(u"rail_path_direction");
@@ -95,7 +94,7 @@ void RailActivatorComponent::OnUse(Entity* originator) {
void RailActivatorComponent::OnRailMovementReady(Entity* originator) const {
// Stun the originator
GameMessages::SendSetStunned(originator->GetObjectID(), PUSH, originator->GetSystemAddress(), LWOOBJID_EMPTY,
GameMessages::SendSetStunned(originator->GetObjectID(), eStateChangeType::PUSH, originator->GetSystemAddress(), LWOOBJID_EMPTY,
true, true, true, true, true, true, true
);
@@ -123,7 +122,7 @@ void RailActivatorComponent::OnRailMovementReady(Entity* originator) const {
void RailActivatorComponent::OnCancelRailMovement(Entity* originator) {
// Remove the stun from the originator
GameMessages::SendSetStunned(originator->GetObjectID(), POP, originator->GetSystemAddress(), LWOOBJID_EMPTY,
GameMessages::SendSetStunned(originator->GetObjectID(), eStateChangeType::POP, originator->GetSystemAddress(), LWOOBJID_EMPTY,
true, true, true, true, true, true, true
);

View File

@@ -4,6 +4,7 @@
#include <string>
#include "dCommonVars.h"
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* Component that handles the traveling using rails, e.g. the ninjago posts that can be used to travel using Spinjitzu.
@@ -14,7 +15,7 @@ public:
explicit RailActivatorComponent(Entity* parent, int32_t componentID);
~RailActivatorComponent() override;
static const uint32_t ComponentType = COMPONENT_TYPE_RAIL_ACTIVATOR;
static const eReplicaComponentType ComponentType = eReplicaComponentType::RAIL_ACTIVATOR;
/**
* Handles the OnUse event from some entity, initiates the rail movement

View File

@@ -7,13 +7,16 @@
#include "dLogger.h"
#include "CharacterComponent.h"
#include "MissionComponent.h"
#include "MissionTaskType.h"
#include "eMissionTaskType.h"
#include "eTriggerEventType.h"
#include "dServer.h"
#include "PacketUtils.h"
#include "Spawner.h"
#include "MovingPlatformComponent.h"
#include "Preconditions.h"
#include "Loot.h"
#include "TeamManager.h"
#include "CppScripts.h"
@@ -51,7 +54,7 @@ RebuildComponent::~RebuildComponent() {
}
void RebuildComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
if (m_Parent->GetComponent(COMPONENT_TYPE_DESTROYABLE) == nullptr) {
if (m_Parent->GetComponent(eReplicaComponentType::DESTROYABLE) == nullptr) {
if (bIsInitialUpdate) {
outBitStream->Write(false);
}
@@ -464,12 +467,20 @@ void RebuildComponent::CompleteRebuild(Entity* user) {
auto* builder = GetBuilder();
if (builder != nullptr) {
auto* missionComponent = builder->GetComponent<MissionComponent>();
if (missionComponent != nullptr) {
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_ActivityId);
if (builder) {
auto* team = TeamManager::Instance()->GetTeam(builder->GetObjectID());
if (team) {
for (const auto memberId : team->members) { // progress missions for all team members
auto* member = EntityManager::Instance()->GetEntity(memberId);
if (member) {
auto* missionComponent = member->GetComponent<MissionComponent>();
if (missionComponent) missionComponent->Progress(eMissionTaskType::ACTIVITY, m_ActivityId);
}
}
} else{
auto* missionComponent = builder->GetComponent<MissionComponent>();
if (missionComponent) missionComponent->Progress(eMissionTaskType::ACTIVITY, m_ActivityId);
}
LootGenerator::Instance().DropActivityLoot(builder, m_Parent, m_ActivityId, 1);
}
@@ -485,6 +496,8 @@ void RebuildComponent::CompleteRebuild(Entity* user) {
for (const auto& callback : m_RebuildCompleteCallbacks)
callback(user);
m_Parent->TriggerEvent(eTriggerEventType::REBUILD_COMPLETE, user);
auto* movingPlatform = m_Parent->GetComponent<MovingPlatformComponent>();
if (movingPlatform != nullptr) {
movingPlatform->OnCompleteRebuild();

View File

@@ -9,6 +9,7 @@
#include "ScriptedActivityComponent.h"
#include "Preconditions.h"
#include "Component.h"
#include "eReplicaComponentType.h"
class Entity;
@@ -19,7 +20,7 @@ class Entity;
*/
class RebuildComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_REBUILD;
static const eReplicaComponentType ComponentType = eReplicaComponentType::QUICK_BUILD;
RebuildComponent(Entity* entity);
~RebuildComponent() override;

View File

@@ -20,9 +20,9 @@ RenderComponent::RenderComponent(Entity* parent) : Component(parent) {
return;
/*
auto* table = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
auto* table = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
const auto entry = table->GetByIDAndType(parent->GetLOT(), COMPONENT_TYPE_RENDER);
const auto entry = table->GetByIDAndType(parent->GetLOT(), eReplicaComponentType::RENDER);
std::stringstream query;

View File

@@ -8,6 +8,7 @@
#include "AMFFormat.h"
#include "Component.h"
#include "eReplicaComponentType.h"
class Entity;
@@ -55,7 +56,7 @@ struct Effect {
*/
class RenderComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_RENDER;
static const eReplicaComponentType ComponentType = eReplicaComponentType::RENDER;
RenderComponent(Entity* entity);
~RenderComponent() override;

View File

@@ -11,6 +11,7 @@
#include "NiPoint3.h"
#include "NiQuaternion.h"
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* Component that handles rigid bodies that can be interacted with, mostly client-side rendered. An example is the
@@ -18,7 +19,7 @@
*/
class RigidbodyPhantomPhysicsComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_PHANTOM_PHYSICS;
static const eReplicaComponentType ComponentType = eReplicaComponentType::PHANTOM_PHYSICS;
RigidbodyPhantomPhysicsComponent(Entity* parent);
~RigidbodyPhantomPhysicsComponent() override;

View File

@@ -3,6 +3,7 @@
#include "Entity.h"
#include "GameMessages.h"
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* Component that handles the LUP/WBL rocket launchpad that can be interacted with to travel to WBL worlds.
@@ -10,7 +11,7 @@
*/
class RocketLaunchLupComponent : public Component {
public:
static const uint32_t ComponentType = eReplicaComponentType::COMPONENT_TYPE_ROCKET_LAUNCH_LUP;
static const eReplicaComponentType ComponentType = eReplicaComponentType::ROCKET_LAUNCH_LUP;
/**
* Constructor for this component, builds the m_LUPWorlds vector

View File

@@ -9,6 +9,7 @@
#include "BitStream.h"
#include "Entity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
class PreconditionExpression;
@@ -17,7 +18,7 @@ class PreconditionExpression;
*/
class RocketLaunchpadControlComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_ROCKET_LAUNCH;
static const eReplicaComponentType ComponentType = eReplicaComponentType::ROCKET_LAUNCH;
RocketLaunchpadControlComponent(Entity* parent, int rocketId);
~RocketLaunchpadControlComponent() override;

View File

@@ -16,11 +16,20 @@
#include "GeneralUtils.h"
#include "dZoneManager.h"
#include "dConfig.h"
#include "InventoryComponent.h"
#include "DestroyableComponent.h"
#include "dMessageIdentifiers.h"
#include "Loot.h"
#include "eMissionTaskType.h"
#include "CDCurrencyTableTable.h"
#include "CDActivityRewardsTable.h"
#include "CDActivitiesTable.h"
ScriptedActivityComponent::ScriptedActivityComponent(Entity* parent, int activityID) : Component(parent) {
CDActivitiesTable* activitiesTable = CDClientManager::Instance()->GetTable<CDActivitiesTable>("Activities");
std::vector<CDActivities> activities = activitiesTable->Query([=](CDActivities entry) {return (entry.ActivityID == activityID); });
m_ActivityID = activityID;
CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>();
std::vector<CDActivities> activities = activitiesTable->Query([=](CDActivities entry) {return (entry.ActivityID == m_ActivityID); });
for (CDActivities activity : activities) {
m_ActivityInfo = activity;
@@ -48,7 +57,7 @@ ScriptedActivityComponent::ScriptedActivityComponent(Entity* parent, int activit
if (destroyableComponent) {
// check for LMIs and set the loot LMIs
CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance()->GetTable<CDActivityRewardsTable>("ActivityRewards");
CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance().GetTable<CDActivityRewardsTable>();
std::vector<CDActivityRewards> activityRewards = activityRewardsTable->Query([=](CDActivityRewards entry) {return (entry.LootMatrixIndex == destroyableComponent->GetLootMatrixID()); });
uint32_t startingLMI = 0;
@@ -88,6 +97,21 @@ void ScriptedActivityComponent::Serialize(RakNet::BitStream* outBitStream, bool
}
}
void ScriptedActivityComponent::ReloadConfig() {
CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>();
std::vector<CDActivities> activities = activitiesTable->Query([=](CDActivities entry) {return (entry.ActivityID == m_ActivityID); });
for (auto activity : activities) {
auto mapID = m_ActivityInfo.instanceMapID;
if ((mapID == 1203 || mapID == 1261 || mapID == 1303 || mapID == 1403) && Game::config->GetValue("solo_racing") == "1") {
m_ActivityInfo.minTeamSize = 1;
m_ActivityInfo.minTeams = 1;
} else {
m_ActivityInfo.minTeamSize = activity.minTeamSize;
m_ActivityInfo.minTeams = activity.minTeams;
}
}
}
void ScriptedActivityComponent::HandleMessageBoxResponse(Entity* player, const std::string& id) {
if (m_ActivityInfo.ActivityID == 103) {
return;
@@ -117,7 +141,7 @@ void ScriptedActivityComponent::PlayerJoin(Entity* player) {
}
void ScriptedActivityComponent::PlayerJoinLobby(Entity* player) {
if (!m_Parent->HasComponent(COMPONENT_TYPE_REBUILD))
if (!m_Parent->HasComponent(eReplicaComponentType::QUICK_BUILD))
GameMessages::SendMatchResponse(player, player->GetSystemAddress(), 0); // tell the client they joined a lobby
LobbyPlayer* newLobbyPlayer = new LobbyPlayer();
newLobbyPlayer->entityID = player->GetObjectID();
@@ -191,7 +215,7 @@ void ScriptedActivityComponent::PlayerLeave(LWOOBJID playerID) {
}
void ScriptedActivityComponent::Update(float deltaTime) {
std::vector<Lobby*> lobbiesToRemove{};
// Ticks all the lobbies, not applicable for non-instance activities
for (Lobby* lobby : m_Queue) {
for (LobbyPlayer* player : lobby->players) {
@@ -202,6 +226,11 @@ void ScriptedActivityComponent::Update(float deltaTime) {
}
}
if (lobby->players.empty()) {
lobbiesToRemove.push_back(lobby);
continue;
}
// Update the match time for all players
if (m_ActivityInfo.maxTeamSize != 1 && lobby->players.size() >= m_ActivityInfo.minTeamSize
|| m_ActivityInfo.maxTeamSize == 1 && lobby->players.size() >= m_ActivityInfo.minTeams) {
@@ -245,13 +274,17 @@ void ScriptedActivityComponent::Update(float deltaTime) {
// The timer has elapsed, start the instance
if (lobby->timer <= 0.0f) {
Game::logger->Log("ScriptedActivityComponent", "Setting up instance.");
ActivityInstance* instance = NewInstance();
LoadPlayersIntoInstance(instance, lobby->players);
RemoveLobby(lobby);
instance->StartZone();
lobbiesToRemove.push_back(lobby);
}
}
while (!lobbiesToRemove.empty()) {
RemoveLobby(lobbiesToRemove.front());
lobbiesToRemove.erase(lobbiesToRemove.begin());
}
}
void ScriptedActivityComponent::RemoveLobby(Lobby* lobby) {
@@ -270,7 +303,7 @@ bool ScriptedActivityComponent::HasLobby() const {
bool ScriptedActivityComponent::IsValidActivity(Entity* player) {
// Makes it so that scripted activities with an unimplemented map cannot be joined
/*if (player->GetGMLevel() < GAME_MASTER_LEVEL_DEVELOPER && (m_ActivityInfo.instanceMapID == 1302 || m_ActivityInfo.instanceMapID == 1301)) {
/*if (player->GetGMLevel() < eGameMasterLevel::DEVELOPER && (m_ActivityInfo.instanceMapID == 1302 || m_ActivityInfo.instanceMapID == 1301)) {
if (m_Parent->GetLOT() == 4860) {
auto* missionComponent = player->GetComponent<MissionComponent>();
missionComponent->CompleteMission(229);
@@ -524,18 +557,18 @@ void ActivityInstance::StartZone() {
void ActivityInstance::RewardParticipant(Entity* participant) {
auto* missionComponent = participant->GetComponent<MissionComponent>();
if (missionComponent) {
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_ActivityInfo.ActivityID);
missionComponent->Progress(eMissionTaskType::ACTIVITY, m_ActivityInfo.ActivityID);
}
// First, get the activity data
auto* activityRewardsTable = CDClientManager::Instance()->GetTable<CDActivityRewardsTable>("ActivityRewards");
auto* activityRewardsTable = CDClientManager::Instance().GetTable<CDActivityRewardsTable>();
std::vector<CDActivityRewards> activityRewards = activityRewardsTable->Query([=](CDActivityRewards entry) { return (entry.objectTemplate == m_ActivityInfo.ActivityID); });
if (!activityRewards.empty()) {
uint32_t minCoins = 0;
uint32_t maxCoins = 0;
auto* currencyTableTable = CDClientManager::Instance()->GetTable<CDCurrencyTableTable>("CurrencyTable");
auto* currencyTableTable = CDClientManager::Instance().GetTable<CDCurrencyTableTable>();
std::vector<CDCurrencyTable> currencyTable = currencyTableTable->Query([=](CDCurrencyTable entry) { return (entry.currencyIndex == activityRewards[0].CurrencyIndex && entry.npcminlevel == 1); });
if (!currencyTable.empty()) {

View File

@@ -11,6 +11,9 @@
#include "BitStream.h"
#include "Entity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
#include "CDActivitiesTable.h"
/**
* Represents an instance of an activity, having participants and score
@@ -153,7 +156,7 @@ struct ActivityPlayer {
*/
class ScriptedActivityComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_SCRIPTED_ACTIVITY;
static const eReplicaComponentType ComponentType = eReplicaComponentType::SCRIPTED_ACTIVITY;
ScriptedActivityComponent(Entity* parent, int activityID);
~ScriptedActivityComponent() override;
@@ -276,6 +279,12 @@ public:
*/
ActivityInstance* GetInstance(const LWOOBJID playerID);
/**
* @brief Reloads the config settings for this component
*
*/
void ReloadConfig();
/**
* Removes all the instances
*/
@@ -361,6 +370,12 @@ private:
* LMIs for team sizes
*/
std::unordered_map<uint32_t, uint32_t> m_ActivityLootMatrices;
/**
* The activity id
*
*/
int32_t m_ActivityID;
};
#endif // SCRIPTEDACTIVITYCOMPONENT_H

View File

@@ -3,6 +3,7 @@
#include "NiPoint3.h"
#include "Entity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* Parameters for the shooting gallery that change during playtime
@@ -72,7 +73,7 @@ struct StaticShootingGalleryParams {
*/
class ShootingGalleryComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_SHOOTING_GALLERY;
static const eReplicaComponentType ComponentType = eReplicaComponentType::SHOOTING_GALLERY;
explicit ShootingGalleryComponent(Entity* parent);
~ShootingGalleryComponent();

View File

@@ -11,6 +11,7 @@
#include "NiPoint3.h"
#include "NiQuaternion.h"
#include "Component.h"
#include "eReplicaComponentType.h"
class Entity;
@@ -27,7 +28,7 @@ enum class eClimbableType : int32_t {
*/
class SimplePhysicsComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_SIMPLE_PHYSICS;
static const eReplicaComponentType ComponentType = eReplicaComponentType::SIMPLE_PHYSICS;
SimplePhysicsComponent(uint32_t componentID, Entity* parent);
~SimplePhysicsComponent() override;

View File

@@ -19,11 +19,18 @@
#include "BaseCombatAIComponent.h"
#include "ScriptComponent.h"
#include "BuffComponent.h"
#include "EchoStartSkill.h"
#include "dMessageIdentifiers.h"
#include "DoClientProjectileImpact.h"
#include "CDClientManager.h"
#include "CDSkillBehaviorTable.h"
ProjectileSyncEntry::ProjectileSyncEntry() {
}
std::unordered_map<uint32_t, uint32_t> SkillComponent::m_skillBehaviorCache = {};
bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t skillUid, RakNet::BitStream* bitStream, const LWOOBJID target, uint32_t skillID) {
auto* context = new BehaviorContext(this->m_Parent->GetObjectID());
@@ -123,10 +130,14 @@ void SkillComponent::RegisterPlayerProjectile(const LWOOBJID projectileId, Behav
}
void SkillComponent::Update(const float deltaTime) {
if (!m_Parent->HasComponent(COMPONENT_TYPE_BASE_COMBAT_AI) && m_Parent->GetLOT() != 1) {
if (!m_Parent->HasComponent(eReplicaComponentType::BASE_COMBAT_AI) && m_Parent->GetLOT() != 1) {
CalculateUpdate(deltaTime);
}
if (m_Parent->IsPlayer()) {
for (const auto& pair : this->m_managedBehaviors) pair.second->UpdatePlayerSyncs(deltaTime);
}
std::map<uint32_t, BehaviorContext*> keep{};
for (const auto& pair : this->m_managedBehaviors) {
@@ -181,17 +192,19 @@ void SkillComponent::Reset() {
}
void SkillComponent::Interrupt() {
if (m_Parent->IsPlayer()) return;
// TODO: need to check immunities on the destroyable component, but they aren't implemented
auto* combat = m_Parent->GetComponent<BaseCombatAIComponent>();
if (combat != nullptr && combat->GetStunImmune()) {
return;
}
if (combat != nullptr && combat->GetStunImmune()) return;
for (const auto& behavior : this->m_managedBehaviors) {
for (const auto& behaviorEndEntry : behavior.second->endEntries) {
behaviorEndEntry.behavior->End(behavior.second, behaviorEndEntry.branchContext, behaviorEndEntry.second);
}
behavior.second->endEntries.clear();
if (m_Parent->IsPlayer()) continue;
behavior.second->Interrupt();
}
}
void SkillComponent::RegisterCalculatedProjectile(const LWOOBJID projectileId, BehaviorContext* context, const BehaviorBranchContext& branch, const LOT lot, const float maxTime,
@@ -214,6 +227,29 @@ void SkillComponent::RegisterCalculatedProjectile(const LWOOBJID projectileId, B
this->m_managedProjectiles.push_back(entry);
}
bool SkillComponent::CastSkill(const uint32_t skillId, LWOOBJID target, const LWOOBJID optionalOriginatorID) {
uint32_t behaviorId = -1;
// try to find it via the cache
const auto& pair = m_skillBehaviorCache.find(skillId);
// if it's not in the cache look it up and cache it
if (pair == m_skillBehaviorCache.end()) {
auto skillTable = CDClientManager::Instance().GetTable<CDSkillBehaviorTable>();
behaviorId = skillTable->GetSkillByID(skillId).behaviorID;
m_skillBehaviorCache.insert_or_assign(skillId, behaviorId);
} else {
behaviorId = pair->second;
}
// check to see if we got back a valid behavior
if (behaviorId == -1) {
Game::logger->LogDebug("SkillComponent", "Tried to cast skill %i but found no behavior", skillId);
return false;
}
return CalculateBehavior(skillId, behaviorId, target, false, false, optionalOriginatorID).success;
}
SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, const uint32_t behaviorId, const LWOOBJID target, const bool ignoreTarget, const bool clientInitalized, const LWOOBJID originatorOverride) {
auto* bitStream = new RakNet::BitStream();
@@ -246,12 +282,13 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c
if (!clientInitalized) {
// Echo start skill
GameMessages::EchoStartSkill start;
EchoStartSkill start;
start.iCastType = 0;
start.skillID = skillId;
start.uiSkillHandle = context->skillUId;
start.optionalOriginatorID = context->originator;
start.optionalTargetID = target;
auto* originator = EntityManager::Instance()->GetEntity(context->originator);
@@ -319,34 +356,7 @@ void SkillComponent::CalculateUpdate(const float deltaTime) {
const auto distance = Vector3::DistanceSquared(targetPosition, closestPoint);
if (distance > 3 * 3) {
/*
if (entry.TrackTarget && distance <= entry.TrackRadius)
{
const auto rotation = NiQuaternion::LookAtUnlocked(position, targetPosition);
const auto speed = entry.Velocity.Length();
const auto homingTarget = rotation.GetForwardVector() * speed;
Vector3 homing;
// Move towards
const auto difference = homingTarget - entry.Velocity;
const auto mag = difference.Length();
if (mag <= speed || mag == 0)
{
homing = homingTarget;
}
else
{
entry.Velocity + homingTarget / mag * speed;
}
entry.Velocity = homing;
}
*/
// TODO There is supposed to be an implementation for homing projectiles here
continue;
}
@@ -416,7 +426,7 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry)
behavior->Calculate(entry.context, bitStream, entry.branchContext);
GameMessages::DoClientProjectileImpact projectileImpact;
DoClientProjectileImpact projectileImpact;
projectileImpact.sBitStream.assign((char*)bitStream->GetData(), bitStream->GetNumberOfBytesUsed());
projectileImpact.i64OwnerID = this->m_Parent->GetObjectID();
@@ -465,7 +475,7 @@ void SkillComponent::HandleUnCast(const uint32_t behaviorId, const LWOOBJID targ
delete context;
}
SkillComponent::SkillComponent(Entity* parent) : Component(parent) {
SkillComponent::SkillComponent(Entity* parent): Component(parent) {
this->m_skillUid = 0;
}

View File

@@ -13,6 +13,7 @@
#include "Component.h"
#include "Entity.h"
#include "dLogger.h"
#include "eReplicaComponentType.h"
struct ProjectileSyncEntry {
LWOOBJID id = LWOOBJID_EMPTY;
@@ -58,7 +59,7 @@ struct SkillExecutionResult {
*/
class SkillComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_SKILL;
static const eReplicaComponentType ComponentType = eReplicaComponentType::SKILL;
explicit SkillComponent(Entity* parent);
~SkillComponent() override;
@@ -119,6 +120,15 @@ public:
*/
void RegisterPlayerProjectile(LWOOBJID projectileId, BehaviorContext* context, const BehaviorBranchContext& branch, LOT lot);
/**
* Wrapper for CalculateBehavior that mimics the call structure in scripts and helps reduce magic numbers
* @param skillId the skill to cast
* @param target the target of the skill
* @param optionalOriginatorID change the originator of the skill
* @return if the case succeeded
*/
bool CastSkill(const uint32_t skillId, LWOOBJID target = LWOOBJID_EMPTY, const LWOOBJID optionalOriginatorID = LWOOBJID_EMPTY);
/**
* Initializes a server-side skill calculation.
* @param skillId the skill ID
@@ -190,6 +200,11 @@ private:
*/
uint32_t m_skillUid;
/**
* Cache for looking up a behavior id via a skill ID
*/
static std::unordered_map<uint32_t, uint32_t> m_skillBehaviorCache;
/**
* Sync a server-side projectile calculation.
* @param entry the projectile information

View File

@@ -3,6 +3,7 @@
#include "Entity.h"
#include "GUID.h"
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* Music that should be played by the client
@@ -19,7 +20,7 @@ struct MusicCue {
*/
class SoundTriggerComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_SOUND_TRIGGER;
static const eReplicaComponentType ComponentType = eReplicaComponentType::SOUND_TRIGGER;
explicit SoundTriggerComponent(Entity* parent);
~SoundTriggerComponent() override;

View File

@@ -1,5 +1,6 @@
#include "SwitchComponent.h"
#include "EntityManager.h"
#include "eTriggerEventType.h"
std::vector<SwitchComponent*> SwitchComponent::petSwitches;
@@ -42,7 +43,7 @@ void SwitchComponent::EntityEnter(Entity* entity) {
}
m_Active = true;
if (!m_Parent) return;
m_Parent->TriggerEvent("OnActivated");
m_Parent->TriggerEvent(eTriggerEventType::ACTIVATED, entity);
const auto grpName = m_Parent->GetVarAsString(u"grp_name");
@@ -78,7 +79,7 @@ void SwitchComponent::Update(float deltaTime) {
if (m_Timer <= 0.0f) {
m_Active = false;
if (!m_Parent) return;
m_Parent->TriggerEvent("OnDectivated");
m_Parent->TriggerEvent(eTriggerEventType::DEACTIVATED, m_Parent);
const auto grpName = m_Parent->GetVarAsString(u"grp_name");

View File

@@ -9,13 +9,14 @@
#include "BouncerComponent.h"
#include <algorithm>
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* A component for switches in game, including pet triggered switches.
*/
class SwitchComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_SWITCH;
static const eReplicaComponentType ComponentType = eReplicaComponentType::SWITCH;
SwitchComponent(Entity* parent);
~SwitchComponent() override;

View File

@@ -0,0 +1,423 @@
#include "TriggerComponent.h"
#include "dZoneManager.h"
#include "TeamManager.h"
#include "eTriggerCommandType.h"
#include "eMissionTaskType.h"
#include "ePhysicsEffectType.h"
#include "CharacterComponent.h"
#include "ControllablePhysicsComponent.h"
#include "MissionComponent.h"
#include "PhantomPhysicsComponent.h"
#include "Player.h"
#include "RebuildComponent.h"
#include "SkillComponent.h"
#include "eEndBehavior.h"
TriggerComponent::TriggerComponent(Entity* parent, const std::string triggerInfo): Component(parent) {
m_Parent = parent;
m_Trigger = nullptr;
std::vector<std::string> tokens = GeneralUtils::SplitString(triggerInfo, ':');
uint32_t sceneID;
GeneralUtils::TryParse<uint32_t>(tokens.at(0), sceneID);
uint32_t triggerID;
GeneralUtils::TryParse<uint32_t>(tokens.at(1), triggerID);
m_Trigger = dZoneManager::Instance()->GetZone()->GetTrigger(sceneID, triggerID);
if (!m_Trigger) m_Trigger = new LUTriggers::Trigger();
}
void TriggerComponent::TriggerEvent(eTriggerEventType event, Entity* optionalTarget) {
if (m_Trigger && m_Trigger->enabled) {
for (LUTriggers::Event* triggerEvent : m_Trigger->events) {
if (triggerEvent->id == event) {
for (LUTriggers::Command* command : triggerEvent->commands) {
HandleTriggerCommand(command, optionalTarget);
}
}
}
}
}
void TriggerComponent::HandleTriggerCommand(LUTriggers::Command* command, Entity* optionalTarget) {
auto argArray = GeneralUtils::SplitString(command->args, ',');
// determine targets
std::vector<Entity*> targetEntities = GatherTargets(command, optionalTarget);
// if we have no targets, then we are done
if (targetEntities.empty()) return;
for (Entity* targetEntity : targetEntities) {
if (!targetEntity) continue;
switch (command->id) {
case eTriggerCommandType::ZONE_PLAYER: break;
case eTriggerCommandType::FIRE_EVENT:
HandleFireEvent(targetEntity, command->args);
break;
case eTriggerCommandType::DESTROY_OBJ:
HandleDestroyObject(targetEntity, command->args);
break;
case eTriggerCommandType::TOGGLE_TRIGGER:
HandleToggleTrigger(targetEntity, command->args);
break;
case eTriggerCommandType::RESET_REBUILD:
HandleResetRebuild(targetEntity, command->args);
break;
case eTriggerCommandType::SET_PATH: break;
case eTriggerCommandType::SET_PICK_TYPE: break;
case eTriggerCommandType::MOVE_OBJECT:
HandleMoveObject(targetEntity, argArray);
break;
case eTriggerCommandType::ROTATE_OBJECT:
HandleRotateObject(targetEntity, argArray);
break;
case eTriggerCommandType::PUSH_OBJECT:
HandlePushObject(targetEntity, argArray);
break;
case eTriggerCommandType::REPEL_OBJECT:
HandleRepelObject(targetEntity, command->args);
break;
case eTriggerCommandType::SET_TIMER: break;
case eTriggerCommandType::CANCEL_TIMER: break;
case eTriggerCommandType::PLAY_CINEMATIC:
HandlePlayCinematic(targetEntity, argArray);
break;
case eTriggerCommandType::TOGGLE_BBB:
HandleToggleBBB(targetEntity, command->args);
break;
case eTriggerCommandType::UPDATE_MISSION:
HandleUpdateMission(targetEntity, argArray);
break;
case eTriggerCommandType::SET_BOUNCER_STATE: break;
case eTriggerCommandType::BOUNCE_ALL_ON_BOUNCER: break;
case eTriggerCommandType::TURN_AROUND_ON_PATH: break;
case eTriggerCommandType::GO_FORWARD_ON_PATH: break;
case eTriggerCommandType::GO_BACKWARD_ON_PATH: break;
case eTriggerCommandType::STOP_PATHING: break;
case eTriggerCommandType::START_PATHING: break;
case eTriggerCommandType::LOCK_OR_UNLOCK_CONTROLS: break;
case eTriggerCommandType::PLAY_EFFECT:
HandlePlayEffect(targetEntity, argArray);
break;
case eTriggerCommandType::STOP_EFFECT:
GameMessages::SendStopFXEffect(targetEntity, true, command->args);
break;
case eTriggerCommandType::CAST_SKILL:
HandleCastSkill(targetEntity, command->args);
break;
case eTriggerCommandType::DISPLAY_ZONE_SUMMARY:
GameMessages::SendDisplayZoneSummary(targetEntity->GetObjectID(), targetEntity->GetSystemAddress(), false, command->args == "1", m_Parent->GetObjectID());
break;
case eTriggerCommandType::SET_PHYSICS_VOLUME_EFFECT:
HandleSetPhysicsVolumeEffect(targetEntity, argArray);
break;
case eTriggerCommandType::SET_PHYSICS_VOLUME_STATUS:
HandleSetPhysicsVolumeStatus(targetEntity, command->args);
break;
case eTriggerCommandType::SET_MODEL_TO_BUILD: break;
case eTriggerCommandType::SPAWN_MODEL_BRICKS: break;
case eTriggerCommandType::ACTIVATE_SPAWNER_NETWORK:
HandleActivateSpawnerNetwork(command->args);
break;
case eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK:
HandleDeactivateSpawnerNetwork(command->args);
break;
case eTriggerCommandType::RESET_SPAWNER_NETWORK:
HandleResetSpawnerNetwork(command->args);
break;
case eTriggerCommandType::DESTROY_SPAWNER_NETWORK_OBJECTS:
HandleDestroySpawnerNetworkObjects(command->args);
break;
case eTriggerCommandType::GO_TO_WAYPOINT: break;
case eTriggerCommandType::ACTIVATE_PHYSICS:
HandleActivatePhysics(targetEntity, command->args);
break;
// DEPRECATED BLOCK START
case eTriggerCommandType::ACTIVATE_MUSIC_CUE: break;
case eTriggerCommandType::DEACTIVATE_MUSIC_CUE: break;
case eTriggerCommandType::FLASH_MUSIC_CUE: break;
case eTriggerCommandType::SET_MUSIC_PARAMETER: break;
case eTriggerCommandType::PLAY_2D_AMBIENT_SOUND: break;
case eTriggerCommandType::STOP_2D_AMBIENT_SOUND: break;
case eTriggerCommandType::PLAY_3D_AMBIENT_SOUND: break;
case eTriggerCommandType::STOP_3D_AMBIENT_SOUND: break;
case eTriggerCommandType::ACTIVATE_MIXER_PROGRAM: break;
case eTriggerCommandType::DEACTIVATE_MIXER_PROGRAM: break;
// DEPRECATED BLOCK END
default:
Game::logger->LogDebug("TriggerComponent", "Event %i was not handled!", command->id);
break;
}
}
}
std::vector<Entity*> TriggerComponent::GatherTargets(LUTriggers::Command* command, Entity* optionalTarget) {
std::vector<Entity*> entities = {};
if (command->target == "self") entities.push_back(m_Parent);
else if (command->target == "zone") { /*TODO*/ }
else if (command->target == "target" && optionalTarget) entities.push_back(optionalTarget);
else if (command->target == "targetTeam" && optionalTarget) {
auto* team = TeamManager::Instance()->GetTeam(optionalTarget->GetObjectID());
for (const auto memberId : team->members) {
auto* member = EntityManager::Instance()->GetEntity(memberId);
if (member) entities.push_back(member);
}
} else if (command->target == "objGroup") entities = EntityManager::Instance()->GetEntitiesInGroup(command->targetName);
else if (command->target == "allPlayers") {
for (auto* player : Player::GetAllPlayers()) {
entities.push_back(player);
}
} else if (command->target == "allNPCs") { /*UNUSED*/ }
return entities;
}
void TriggerComponent::HandleFireEvent(Entity* targetEntity, std::string args) {
for (CppScripts::Script* script : CppScripts::GetEntityScripts(targetEntity)) {
script->OnFireEventServerSide(targetEntity, m_Parent, args, 0, 0, 0);
}
}
void TriggerComponent::HandleDestroyObject(Entity* targetEntity, std::string args){
uint32_t killType;
GeneralUtils::TryParse<uint32_t>(args, killType);
targetEntity->Smash(m_Parent->GetObjectID(), static_cast<eKillType>(killType));
}
void TriggerComponent::HandleToggleTrigger(Entity* targetEntity, std::string args){
auto* triggerComponent = targetEntity->GetComponent<TriggerComponent>();
if (!triggerComponent) {
Game::logger->Log("TriggerComponent::HandleToggleTrigger", "Trigger component not found!");
return;
}
triggerComponent->SetTriggerEnabled(args == "1");
}
void TriggerComponent::HandleResetRebuild(Entity* targetEntity, std::string args){
auto* rebuildComponent = targetEntity->GetComponent<RebuildComponent>();
if (!rebuildComponent) {
Game::logger->Log("TriggerComponent::HandleResetRebuild", "Rebuild component not found!");
return;
}
rebuildComponent->ResetRebuild(args == "1");
}
void TriggerComponent::HandleMoveObject(Entity* targetEntity, std::vector<std::string> argArray){
if (argArray.size() <= 2) return;
auto position = targetEntity->GetPosition();
NiPoint3 offset = NiPoint3::ZERO;
GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), offset);
position += offset;
targetEntity->SetPosition(position);
}
void TriggerComponent::HandleRotateObject(Entity* targetEntity, std::vector<std::string> argArray){
if (argArray.size() <= 2) return;
NiPoint3 vector = NiPoint3::ZERO;
GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), vector);
NiQuaternion rotation = NiQuaternion::FromEulerAngles(vector);
targetEntity->SetRotation(rotation);
}
void TriggerComponent::HandlePushObject(Entity* targetEntity, std::vector<std::string> argArray){
auto* phantomPhysicsComponent = m_Parent->GetComponent<PhantomPhysicsComponent>();
if (!phantomPhysicsComponent) {
Game::logger->Log("TriggerComponent::HandlePushObject", "Phantom Physics component not found!");
return;
}
phantomPhysicsComponent->SetPhysicsEffectActive(true);
phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::PUSH);
phantomPhysicsComponent->SetDirectionalMultiplier(1);
NiPoint3 direction = NiPoint3::ZERO;
GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), direction);
phantomPhysicsComponent->SetDirection(direction);
EntityManager::Instance()->SerializeEntity(m_Parent);
}
void TriggerComponent::HandleRepelObject(Entity* targetEntity, std::string args){
auto* phantomPhysicsComponent = m_Parent->GetComponent<PhantomPhysicsComponent>();
if (!phantomPhysicsComponent) {
Game::logger->Log("TriggerComponent::HandleRepelObject", "Phantom Physics component not found!");
return;
}
float forceMultiplier;
GeneralUtils::TryParse<float>(args, forceMultiplier);
phantomPhysicsComponent->SetPhysicsEffectActive(true);
phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::REPULSE);
phantomPhysicsComponent->SetDirectionalMultiplier(forceMultiplier);
auto triggerPos = m_Parent->GetPosition();
auto targetPos = targetEntity->GetPosition();
// normalize the vectors to get the direction
auto delta = targetPos - triggerPos;
auto length = delta.Length();
NiPoint3 direction = delta / length;
phantomPhysicsComponent->SetDirection(direction);
EntityManager::Instance()->SerializeEntity(m_Parent);
}
void TriggerComponent::HandlePlayCinematic(Entity* targetEntity, std::vector<std::string> argArray) {
float leadIn = -1.0;
auto wait = eEndBehavior::RETURN;
bool unlock = true;
bool leaveLocked = false;
bool hidePlayer = false;
if (argArray.size() >= 2) {
GeneralUtils::TryParse<float>(argArray.at(1), leadIn);
if (argArray.size() >= 3 && argArray.at(2) == "wait") {
wait = eEndBehavior::WAIT;
if (argArray.size() >= 4 && argArray.at(3) == "unlock") {
unlock = false;
if (argArray.size() >= 5 && argArray.at(4) == "leavelocked") {
leaveLocked = true;
if (argArray.size() >= 6 && argArray.at(5) == "hideplayer") {
hidePlayer = true;
}
}
}
}
}
GameMessages::SendPlayCinematic(targetEntity->GetObjectID(), GeneralUtils::UTF8ToUTF16(argArray.at(0)), targetEntity->GetSystemAddress(), true, true, false, false, wait, hidePlayer, leadIn, leaveLocked, unlock);
}
void TriggerComponent::HandleToggleBBB(Entity* targetEntity, std::string args) {
auto* character = targetEntity->GetCharacter();
if (!character) {
Game::logger->Log("TriggerComponent::HandleToggleBBB", "Character was not found!");
return;
}
bool buildMode = !(character->GetBuildMode());
if (args == "enter") buildMode = true;
else if (args == "exit") buildMode = false;
character->SetBuildMode(buildMode);
}
void TriggerComponent::HandleUpdateMission(Entity* targetEntity, std::vector<std::string> argArray) {
// there are only explore tasks used
// If others need to be implemented for modding
// then we need a good way to convert this from a string to that enum
if (argArray.at(0) != "exploretask") return;
MissionComponent* missionComponent = targetEntity->GetComponent<MissionComponent>();
if (!missionComponent){
Game::logger->Log("TriggerComponent::HandleUpdateMission", "Mission component not found!");
return;
}
missionComponent->Progress(eMissionTaskType::EXPLORE, 0, 0, argArray.at(4));
}
void TriggerComponent::HandlePlayEffect(Entity* targetEntity, std::vector<std::string> argArray) {
if (argArray.size() < 3) return;
int32_t effectID = 0;
if (!GeneralUtils::TryParse<int32_t>(argArray.at(1), effectID)) return;
std::u16string effectType = GeneralUtils::UTF8ToUTF16(argArray.at(2));
float priority = 1;
if (argArray.size() == 4) GeneralUtils::TryParse<float>(argArray.at(3), priority);
GameMessages::SendPlayFXEffect(targetEntity, effectID, effectType, argArray.at(0), LWOOBJID_EMPTY, priority);
}
void TriggerComponent::HandleCastSkill(Entity* targetEntity, std::string args){
auto* skillComponent = targetEntity->GetComponent<SkillComponent>();
if (!skillComponent) {
Game::logger->Log("TriggerComponent::HandleCastSkill", "Skill component not found!");
return;
}
uint32_t skillId;
GeneralUtils::TryParse<uint32_t>(args, skillId);
skillComponent->CastSkill(skillId, targetEntity->GetObjectID());
}
void TriggerComponent::HandleSetPhysicsVolumeEffect(Entity* targetEntity, std::vector<std::string> argArray) {
auto* phantomPhysicsComponent = targetEntity->GetComponent<PhantomPhysicsComponent>();
if (!phantomPhysicsComponent) {
Game::logger->Log("TriggerComponent::HandleSetPhysicsVolumeEffect", "Phantom Physics component not found!");
return;
}
phantomPhysicsComponent->SetPhysicsEffectActive(true);
ePhysicsEffectType effectType = ePhysicsEffectType::PUSH;
std::transform(argArray.at(0).begin(), argArray.at(0).end(), argArray.at(0).begin(), ::tolower); //Transform to lowercase
if (argArray.at(0) == "push") effectType = ePhysicsEffectType::PUSH;
else if (argArray.at(0) == "attract") effectType = ePhysicsEffectType::ATTRACT;
else if (argArray.at(0) == "repulse") effectType = ePhysicsEffectType::REPULSE;
else if (argArray.at(0) == "gravity") effectType = ePhysicsEffectType::GRAVITY_SCALE;
else if (argArray.at(0) == "friction") effectType = ePhysicsEffectType::FRICTION;
phantomPhysicsComponent->SetEffectType(effectType);
phantomPhysicsComponent->SetDirectionalMultiplier(std::stof(argArray.at(1)));
if (argArray.size() > 4) {
NiPoint3 direction = NiPoint3::ZERO;
GeneralUtils::TryParse(argArray.at(2), argArray.at(3), argArray.at(4), direction);
phantomPhysicsComponent->SetDirection(direction);
}
if (argArray.size() > 5) {
uint32_t min;
GeneralUtils::TryParse<uint32_t>(argArray.at(6), min);
phantomPhysicsComponent->SetMin(min);
uint32_t max;
GeneralUtils::TryParse<uint32_t>(argArray.at(7), max);
phantomPhysicsComponent->SetMax(max);
}
EntityManager::Instance()->SerializeEntity(targetEntity);
}
void TriggerComponent::HandleSetPhysicsVolumeStatus(Entity* targetEntity, std::string args) {
auto* phantomPhysicsComponent = targetEntity->GetComponent<PhantomPhysicsComponent>();
if (!phantomPhysicsComponent) {
Game::logger->Log("TriggerComponent::HandleSetPhysicsVolumeEffect", "Phantom Physics component not found!");
return;
}
phantomPhysicsComponent->SetPhysicsEffectActive(args == "On");
EntityManager::Instance()->SerializeEntity(targetEntity);
}
void TriggerComponent::HandleActivateSpawnerNetwork(std::string args){
for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) {
if (spawner) spawner->Activate();
}
}
void TriggerComponent::HandleDeactivateSpawnerNetwork(std::string args){
for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) {
if (spawner) spawner->Deactivate();
}
}
void TriggerComponent::HandleResetSpawnerNetwork(std::string args){
for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) {
if (spawner) spawner->Reset();
}
}
void TriggerComponent::HandleDestroySpawnerNetworkObjects(std::string args){
for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) {
if (spawner) spawner->DestroyAllEntities();
}
}
void TriggerComponent::HandleActivatePhysics(Entity* targetEntity, std::string args) {
if (args == "true") {
// TODO add physics entity if there isn't one
} else if (args == "false"){
// TODO remove Phsyics entity if there is one
} else {
Game::logger->LogDebug("TriggerComponent", "Invalid argument for ActivatePhysics Trigger: %s", args.c_str());
}
}

View File

@@ -0,0 +1,48 @@
#ifndef __TRIGGERCOMPONENT__H__
#define __TRIGGERCOMPONENT__H__
#include "Component.h"
#include "LUTriggers.h"
#include "eReplicaComponentType.h"
class TriggerComponent : public Component {
public:
static const eReplicaComponentType ComponentType = eReplicaComponentType::TRIGGER;
explicit TriggerComponent(Entity* parent, const std::string triggerInfo);
void TriggerEvent(eTriggerEventType event, Entity* optionalTarget = nullptr);
LUTriggers::Trigger* GetTrigger() const { return m_Trigger; }
void SetTriggerEnabled(bool enabled){ m_Trigger->enabled = enabled; };
private:
void HandleTriggerCommand(LUTriggers::Command* command, Entity* optionalTarget);
std::vector<Entity*> GatherTargets(LUTriggers::Command* command, Entity* optionalTarget);
// Trigger Event Handlers
void HandleFireEvent(Entity* targetEntity, std::string args);
void HandleDestroyObject(Entity* targetEntity, std::string args);
void HandleToggleTrigger(Entity* targetEntity, std::string args);
void HandleResetRebuild(Entity* targetEntity, std::string args);
void HandleMoveObject(Entity* targetEntity, std::vector<std::string> argArray);
void HandleRotateObject(Entity* targetEntity, std::vector<std::string> argArray);
void HandlePushObject(Entity* targetEntity, std::vector<std::string> argArray);
void HandleRepelObject(Entity* targetEntity, std::string args);
void HandlePlayCinematic(Entity* targetEntity, std::vector<std::string> argArray);
void HandleToggleBBB(Entity* targetEntity, std::string args);
void HandleUpdateMission(Entity* targetEntity, std::vector<std::string> argArray);
void HandlePlayEffect(Entity* targetEntity, std::vector<std::string> argArray);
void HandleCastSkill(Entity* targetEntity, std::string args);
void HandleSetPhysicsVolumeEffect(Entity* targetEntity, std::vector<std::string> argArray);
void HandleSetPhysicsVolumeStatus(Entity* targetEntity, std::string args);
void HandleActivateSpawnerNetwork(std::string args);
void HandleDeactivateSpawnerNetwork(std::string args);
void HandleResetSpawnerNetwork(std::string args);
void HandleDestroySpawnerNetworkObjects(std::string args);
void HandleActivatePhysics(Entity* targetEntity, std::string args);
LUTriggers::Trigger* m_Trigger;
};
#endif //!__TRIGGERCOMPONENT__H__

View File

@@ -3,13 +3,14 @@
#include "BitStream.h"
#include "Entity.h"
#include "Component.h"
#include "eReplicaComponentType.h"
/**
* Physics component for vehicles.
*/
class VehiclePhysicsComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_VEHICLE_PHYSICS;
static const eReplicaComponentType ComponentType = eReplicaComponentType::VEHICLE_PHYSICS;
VehiclePhysicsComponent(Entity* parentEntity);
~VehiclePhysicsComponent() override;

View File

@@ -5,6 +5,11 @@
#include "Game.h"
#include "dServer.h"
#include "CDComponentsRegistryTable.h"
#include "CDVendorComponentTable.h"
#include "CDLootMatrixTable.h"
#include "CDLootTableTable.h"
VendorComponent::VendorComponent(Entity* parent) : Component(parent) {
SetupConstants();
RefreshInventory(true);
@@ -59,13 +64,13 @@ void VendorComponent::RefreshInventory(bool isCreation) {
return;
}
m_Inventory.clear();
auto* lootMatrixTable = CDClientManager::Instance()->GetTable<CDLootMatrixTable>("LootMatrix");
auto* lootMatrixTable = CDClientManager::Instance().GetTable<CDLootMatrixTable>();
std::vector<CDLootMatrix> lootMatrices = lootMatrixTable->Query([=](CDLootMatrix entry) { return (entry.LootMatrixIndex == m_LootMatrixID); });
if (lootMatrices.empty()) return;
// Done with lootMatrix table
auto* lootTableTable = CDClientManager::Instance()->GetTable<CDLootTableTable>("LootTable");
auto* lootTableTable = CDClientManager::Instance().GetTable<CDLootTableTable>();
for (const auto& lootMatrix : lootMatrices) {
int lootTableID = lootMatrix.LootTableIndex;
@@ -118,10 +123,10 @@ void VendorComponent::RefreshInventory(bool isCreation) {
}
void VendorComponent::SetupConstants() {
auto* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
int componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), COMPONENT_TYPE_VENDOR);
auto* compRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
int componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::VENDOR);
auto* vendorComponentTable = CDClientManager::Instance()->GetTable<CDVendorComponentTable>("VendorComponent");
auto* vendorComponentTable = CDClientManager::Instance().GetTable<CDVendorComponentTable>();
std::vector<CDVendorComponent> vendorComps = vendorComponentTable->Query([=](CDVendorComponent entry) { return (entry.id == componentID); });
if (vendorComps.empty()) return;
m_BuyScalar = vendorComps[0].buyScalar;

View File

@@ -7,13 +7,14 @@
#include "Entity.h"
#include "GameMessages.h"
#include "RakNetTypes.h"
#include "eReplicaComponentType.h"
/**
* A component for vendor NPCs. A vendor sells items to the player.
*/
class VendorComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_VENDOR;
static const eReplicaComponentType ComponentType = eReplicaComponentType::VENDOR;
VendorComponent(Entity* parent);
~VendorComponent() override;