mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-02-28 13:49:48 +00:00
Merge branch 'main' into use-npc-paths
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "EntityManager.h"
|
||||
#include "SimplePhysicsComponent.h"
|
||||
#include "dZoneManager.h"
|
||||
#include "CDClientManager.h"
|
||||
|
||||
std::map<LOT, float> MovementAIComponent::m_PhysicsSpeedCache = {};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "CDComponentsRegistryTable.h"
|
||||
#include "CDPhysicsComponentTable.h"
|
||||
#include "dServer.h"
|
||||
#include "EntityInfo.h"
|
||||
|
||||
#include "dpWorld.h"
|
||||
#include "dpEntity.h"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 = {};
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user