Merge branch 'main' into use-npc-paths

This commit is contained in:
Aaron Kimbre
2023-01-07 00:52:22 -06:00
238 changed files with 4420 additions and 2382 deletions

View File

@@ -23,9 +23,9 @@
#include "RebuildComponent.h"
#include "DestroyableComponent.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;
@@ -179,7 +179,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 +192,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) {
return;
}
if (m_Stunned) {
if (stunnedThisFrame) {
m_MovementAI->Stop();
return;
@@ -206,7 +206,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:
@@ -248,13 +248,13 @@ 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;
}
@@ -320,9 +320,9 @@ 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) {
@@ -348,7 +348,7 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) {
}
if (m_Target == LWOOBJID_EMPTY) {
m_State = AiState::idle;
SetAiState(AiState::idle);
return;
}
@@ -375,7 +375,7 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) {
m_MovementAI->Stop();
}
m_State = AiState::aggro;
SetAiState(AiState::aggro);
m_Timer = 0;
@@ -532,11 +532,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 +594,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 +712,7 @@ void BaseCombatAIComponent::OnAggro() {
m_MovementAI->SetDestination(targetPos);
m_State = AiState::tether;
SetAiState(AiState::tether);
}
m_Timer += 0.5f;
@@ -726,7 +738,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

@@ -243,6 +243,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
*/
@@ -374,6 +380,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

@@ -9,6 +9,7 @@
#include "SkillComponent.h"
#include "ControllablePhysicsComponent.h"
#include "EntityManager.h"
#include "CDClientManager.h"
std::unordered_map<int32_t, std::vector<BuffParameter>> BuffComponent::m_Cache{};
@@ -169,17 +170,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);
}
}
}
@@ -212,17 +206,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

@@ -13,6 +13,7 @@
#include "VehiclePhysicsComponent.h"
#include "GameMessages.h"
#include "Item.h"
#include "AMFFormat.h"
CharacterComponent::CharacterComponent(Entity* parent, Character* character) : Component(parent) {
m_Character = character;

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,7 @@
#include "Component.h"
#include "dpCollisionChecks.h"
#include "PhantomPhysicsComponent.h"
#include "eBubbleType.h"
class Entity;
class dpEntity;
@@ -257,6 +258,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 +414,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 +430,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

@@ -28,7 +28,9 @@
#include "CharacterComponent.h"
#include "PossessableComponent.h"
#include "PossessorComponent.h"
#include "InventoryComponent.h"
#include "dZoneManager.h"
#include "WorldConfig.h"
DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) {
m_iArmor = 0;
@@ -53,8 +55,17 @@ 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() {
@@ -104,7 +115,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);
@@ -334,7 +354,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) {
@@ -437,7 +457,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 {
@@ -630,6 +650,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);
@@ -647,6 +668,29 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
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);
@@ -669,13 +713,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);
@@ -738,22 +782,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);
}
}
@@ -783,12 +822,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() {

View File

@@ -7,6 +7,10 @@
#include "Entity.h"
#include "Component.h"
namespace CppScripts {
class Script;
}; //! namespace CppScripts
/**
* Represents the stats of an entity, for example its health, imagination and armor. Also handles factions, which
* indicate which enemies this entity has.
@@ -392,16 +396,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
@@ -422,6 +441,17 @@ public:
*/
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);
private:
/**
* Whether or not the health should be serialized
@@ -478,11 +508,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
*/
@@ -557,6 +582,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,9 @@
#include "dConfig.h"
#include "eItemType.h"
#include "eUnequippableActiveType.h"
#include "CppScripts.h"
InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent) {
InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document): Component(parent) {
this->m_Dirty = true;
this->m_Equipped = {};
this->m_Pushed = {};
@@ -867,6 +868,8 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) {
AddItemSkills(item->GetLot());
EquipScripts(item);
EntityManager::Instance()->SerializeEntity(m_Parent);
}
@@ -895,6 +898,8 @@ void InventoryComponent::UnEquipItem(Item* item) {
PurgeProxies(item);
UnequipScripts(item);
EntityManager::Instance()->SerializeEntity(m_Parent);
// Trigger property event
@@ -904,6 +909,37 @@ void InventoryComponent::UnEquipItem(Item* item) {
}
}
void InventoryComponent::EquipScripts(Item* equippedItem) {
CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
if (!compRegistryTable) return;
int32_t scriptComponentID = compRegistryTable->GetByIDAndType(equippedItem->GetLot(), COMPONENT_TYPE_SCRIPT, -1);
if (scriptComponentID > -1) {
CDScriptComponentTable* scriptCompTable = CDClientManager::Instance()->GetTable<CDScriptComponentTable>("ScriptComponent");
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>("ComponentsRegistry");
if (!compRegistryTable) return;
int32_t scriptComponentID = compRegistryTable->GetByIDAndType(unequippedItem->GetLot(), COMPONENT_TYPE_SCRIPT, -1);
if (scriptComponentID > -1) {
CDScriptComponentTable* scriptCompTable = CDClientManager::Instance()->GetTable<CDScriptComponentTable>("ScriptComponent");
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;
@@ -923,7 +959,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());
@@ -1160,9 +1196,9 @@ 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);
}
}

View File

@@ -19,6 +19,7 @@
#include "ItemSetPassiveAbility.h"
#include "ItemSetPassiveAbilityID.h"
#include "PossessorComponent.h"
#include "eInventoryType.h"
class Entity;
class ItemSet;
@@ -282,7 +283,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
@@ -351,6 +352,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

@@ -7,6 +7,8 @@
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 +18,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 +29,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) {
@@ -60,7 +66,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 +79,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,11 +3,13 @@
#include "Entity.h"
#include "GameMessages.h"
#include "Component.h"
#include "eCharacterVersion.h"
/**
* Component that handles level progression and serilization.
*
*/
class LevelProgressionComponent : public Component {
public:
static const uint32_t ComponentType = eReplicaComponentType::COMPONENT_TYPE_LEVEL_PROGRESSION;
@@ -44,11 +46,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 +90,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

@@ -10,6 +10,7 @@
#include "EntityManager.h"
#include "SimplePhysicsComponent.h"
#include "dZoneManager.h"
#include "CDClientManager.h"
std::map<LOT, float> MovementAIComponent::m_PhysicsSpeedCache = {};

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,9 @@
#include "dCommonVars.h"
#include "EntityManager.h"
#include "Component.h"
#include "eMovementPlatformState.h"
class Path;
/**
* Different types of available platforms
@@ -26,16 +29,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 +42,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
@@ -133,7 +126,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,7 @@
#include "dConfig.h"
#include "dChatFilter.h"
#include "Database.h"
#include "EntityInfo.h"
std::unordered_map<LOT, PetComponent::PetPuzzleData> PetComponent::buildCache{};
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::currentActivities{};
@@ -59,7 +60,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 +119,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);
}
}
}
}
@@ -916,16 +919,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);
});
}

View File

@@ -19,6 +19,7 @@
#include "CDComponentsRegistryTable.h"
#include "CDPhysicsComponentTable.h"
#include "dServer.h"
#include "EntityInfo.h"
#include "dpWorld.h"
#include "dpEntity.h"

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

@@ -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

@@ -109,7 +109,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

@@ -11,6 +11,7 @@
#include "CharacterComponent.h"
#include "UserManager.h"
#include "dLogger.h"
#include "AMFFormat.h"
PropertyEntranceComponent::PropertyEntranceComponent(uint32_t componentID, Entity* parent) : Component(parent) {
this->propertyQueries = {};

View File

@@ -17,6 +17,7 @@
#include "Player.h"
#include "RocketLaunchpadControlComponent.h"
#include "PropertyEntranceComponent.h"
#include "InventoryComponent.h"
#include <vector>
#include "CppScripts.h"
@@ -717,7 +718,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

@@ -21,6 +21,7 @@
#include "dServer.h"
#include "dZoneManager.h"
#include "dConfig.h"
#include "Loot.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288
@@ -98,7 +99,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 +127,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.
@@ -567,12 +553,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 +567,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;
}

View File

@@ -123,7 +123,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

@@ -95,7 +95,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 +123,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

@@ -14,6 +14,8 @@
#include "Spawner.h"
#include "MovingPlatformComponent.h"
#include "Preconditions.h"
#include "Loot.h"
#include "TeamManager.h"
#include "CppScripts.h"
@@ -464,12 +466,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(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_ActivityId);
}
}
} else{
auto* missionComponent = builder->GetComponent<MissionComponent>();
if (missionComponent) missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_ActivityId);
}
LootGenerator::Instance().DropActivityLoot(builder, m_Parent, m_ActivityId, 1);
}

View File

@@ -16,7 +16,10 @@
#include "GeneralUtils.h"
#include "dZoneManager.h"
#include "dConfig.h"
#include "InventoryComponent.h"
#include "DestroyableComponent.h"
#include "dMessageIdentifiers.h"
#include "Loot.h"
ScriptedActivityComponent::ScriptedActivityComponent(Entity* parent, int activityID) : Component(parent) {
m_ActivityID = activityID;
@@ -207,7 +210,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) {
@@ -218,6 +221,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) {
@@ -261,13 +269,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) {

View File

@@ -19,7 +19,9 @@
#include "BaseCombatAIComponent.h"
#include "ScriptComponent.h"
#include "BuffComponent.h"
#include "EchoStartSkill.h"
#include "dMessageIdentifiers.h"
#include "DoClientProjectileImpact.h"
ProjectileSyncEntry::ProjectileSyncEntry() {
}
@@ -181,17 +183,11 @@ 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) {
behavior.second->Interrupt();
}
for (const auto& behavior : this->m_managedBehaviors) behavior.second->Interrupt();
}
void SkillComponent::RegisterCalculatedProjectile(const LWOOBJID projectileId, BehaviorContext* context, const BehaviorBranchContext& branch, const LOT lot, const float maxTime,
@@ -246,12 +242,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 +316,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 +386,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();