mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-23 14:07:20 +00:00
Merge remote-tracking branch 'origin/main' into scripting-lua
This commit is contained in:
commit
ac7823802e
@ -19,6 +19,12 @@ void AndBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStre
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AndBehavior::UnCast(BehaviorContext* context, const BehaviorBranchContext branch) {
|
||||||
|
for (auto behavior : this->m_behaviors) {
|
||||||
|
behavior->UnCast(context, branch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AndBehavior::Load()
|
void AndBehavior::Load()
|
||||||
{
|
{
|
||||||
const auto parameters = GetParameterNames();
|
const auto parameters = GetParameterNames();
|
||||||
|
@ -20,5 +20,7 @@ public:
|
|||||||
|
|
||||||
void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
|
void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
|
||||||
|
|
||||||
|
void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override;
|
||||||
|
|
||||||
void Load() override;
|
void Load() override;
|
||||||
};
|
};
|
||||||
|
@ -14,7 +14,7 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi
|
|||||||
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
||||||
if (destroyableComponent != nullptr) {
|
if (destroyableComponent != nullptr) {
|
||||||
PlayFx(u"onhit", entity->GetObjectID());
|
PlayFx(u"onhit", entity->GetObjectID());
|
||||||
destroyableComponent->Damage(this->m_maxDamage, context->originator);
|
destroyableComponent->Damage(this->m_maxDamage, context->originator, context->skillID);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->m_onSuccess->Handle(context, bitStream, branch);
|
this->m_onSuccess->Handle(context, bitStream, branch);
|
||||||
@ -56,7 +56,7 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi
|
|||||||
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
||||||
if (destroyableComponent != nullptr) {
|
if (destroyableComponent != nullptr) {
|
||||||
PlayFx(u"onhit", entity->GetObjectID());
|
PlayFx(u"onhit", entity->GetObjectID());
|
||||||
destroyableComponent->Damage(damageDealt, context->originator);
|
destroyableComponent->Damage(damageDealt, context->originator, context->skillID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream*
|
|||||||
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
||||||
if (damage != 0 && destroyableComponent != nullptr) {
|
if (damage != 0 && destroyableComponent != nullptr) {
|
||||||
PlayFx(u"onhit", entity->GetObjectID(), 1);
|
PlayFx(u"onhit", entity->GetObjectID(), 1);
|
||||||
destroyableComponent->Damage(damage, context->originator, false);
|
destroyableComponent->Damage(damage, context->originator, context->skillID, false);
|
||||||
context->ScheduleUpdate(branch.target);
|
context->ScheduleUpdate(branch.target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "AreaOfEffectBehavior.h"
|
#include "AreaOfEffectBehavior.h"
|
||||||
#include "DurationBehavior.h"
|
#include "DurationBehavior.h"
|
||||||
#include "TacArcBehavior.h"
|
#include "TacArcBehavior.h"
|
||||||
|
#include "LootBuffBehavior.h"
|
||||||
#include "AttackDelayBehavior.h"
|
#include "AttackDelayBehavior.h"
|
||||||
#include "BasicAttackBehavior.h"
|
#include "BasicAttackBehavior.h"
|
||||||
#include "ChainBehavior.h"
|
#include "ChainBehavior.h"
|
||||||
@ -172,7 +173,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId)
|
|||||||
behavior = new SpeedBehavior(behaviorId);
|
behavior = new SpeedBehavior(behaviorId);
|
||||||
break;
|
break;
|
||||||
case BehaviorTemplates::BEHAVIOR_DARK_INSPIRATION: break;
|
case BehaviorTemplates::BEHAVIOR_DARK_INSPIRATION: break;
|
||||||
case BehaviorTemplates::BEHAVIOR_LOOT_BUFF: break;
|
case BehaviorTemplates::BEHAVIOR_LOOT_BUFF:
|
||||||
|
behavior = new LootBuffBehavior(behaviorId);
|
||||||
|
break;
|
||||||
case BehaviorTemplates::BEHAVIOR_VENTURE_VISION: break;
|
case BehaviorTemplates::BEHAVIOR_VENTURE_VISION: break;
|
||||||
case BehaviorTemplates::BEHAVIOR_SPAWN_OBJECT:
|
case BehaviorTemplates::BEHAVIOR_SPAWN_OBJECT:
|
||||||
behavior = new SpawnBehavior(behaviorId);
|
behavior = new SpawnBehavior(behaviorId);
|
||||||
|
@ -64,8 +64,8 @@ void BehaviorContext::RegisterSyncBehavior(const uint32_t syncId, Behavior* beha
|
|||||||
|
|
||||||
void BehaviorContext::RegisterTimerBehavior(Behavior* behavior, const BehaviorBranchContext& branchContext, const LWOOBJID second)
|
void BehaviorContext::RegisterTimerBehavior(Behavior* behavior, const BehaviorBranchContext& branchContext, const LWOOBJID second)
|
||||||
{
|
{
|
||||||
BehaviorTimerEntry entry
|
BehaviorTimerEntry entry;
|
||||||
;
|
|
||||||
entry.time = branchContext.duration;
|
entry.time = branchContext.duration;
|
||||||
entry.behavior = behavior;
|
entry.behavior = behavior;
|
||||||
entry.branchContext = branchContext;
|
entry.branchContext = branchContext;
|
||||||
|
@ -58,6 +58,8 @@ struct BehaviorContext
|
|||||||
|
|
||||||
float skillTime = 0;
|
float skillTime = 0;
|
||||||
|
|
||||||
|
uint32_t skillID = 0;
|
||||||
|
|
||||||
uint32_t skillUId = 0;
|
uint32_t skillUId = 0;
|
||||||
|
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
|
38
dGame/dBehaviors/LootBuffBehavior.cpp
Normal file
38
dGame/dBehaviors/LootBuffBehavior.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include "LootBuffBehavior.h"
|
||||||
|
|
||||||
|
void LootBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
|
||||||
|
auto target = EntityManager::Instance()->GetEntity(context->caster);
|
||||||
|
if (!target) return;
|
||||||
|
|
||||||
|
auto controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>();
|
||||||
|
if (!controllablePhysicsComponent) return;
|
||||||
|
|
||||||
|
controllablePhysicsComponent->AddPickupRadiusScale(m_Scale);
|
||||||
|
EntityManager::Instance()->SerializeEntity(target);
|
||||||
|
|
||||||
|
if (branch.duration > 0) context->RegisterTimerBehavior(this, branch);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void LootBuffBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
|
||||||
|
Handle(context, bitStream, branch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LootBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
|
||||||
|
auto target = EntityManager::Instance()->GetEntity(context->caster);
|
||||||
|
if (!target) return;
|
||||||
|
|
||||||
|
auto controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>();
|
||||||
|
if (!controllablePhysicsComponent) return;
|
||||||
|
|
||||||
|
controllablePhysicsComponent->RemovePickupRadiusScale(m_Scale);
|
||||||
|
EntityManager::Instance()->SerializeEntity(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LootBuffBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) {
|
||||||
|
UnCast(context, branch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LootBuffBehavior::Load() {
|
||||||
|
this->m_Scale = GetFloat("scale");
|
||||||
|
}
|
32
dGame/dBehaviors/LootBuffBehavior.h
Normal file
32
dGame/dBehaviors/LootBuffBehavior.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Behavior.h"
|
||||||
|
#include "BehaviorBranchContext.h"
|
||||||
|
#include "BehaviorContext.h"
|
||||||
|
#include "ControllablePhysicsComponent.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This is the behavior class to be used for all Loot Buff behavior nodes in the Behavior tree.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class LootBuffBehavior final : public Behavior
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
float m_Scale;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inherited
|
||||||
|
*/
|
||||||
|
|
||||||
|
explicit LootBuffBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {}
|
||||||
|
|
||||||
|
void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
|
||||||
|
|
||||||
|
void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
|
||||||
|
|
||||||
|
void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override;
|
||||||
|
|
||||||
|
void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override;
|
||||||
|
|
||||||
|
void Load() override;
|
||||||
|
};
|
@ -7,62 +7,26 @@
|
|||||||
#include "SkillComponent.h"
|
#include "SkillComponent.h"
|
||||||
#include "DestroyableComponent.h"
|
#include "DestroyableComponent.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* The OverTime behavior is very inconsistent in how it appears in the skill tree vs. how it should behave.
|
|
||||||
*
|
|
||||||
* Items like "Doc in a Box" use an overtime behavior which you would expect have health & armor regen, but is only fallowed by a stun.
|
|
||||||
*
|
|
||||||
* Due to this inconsistency, we have to implement a special case for some items.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void OverTimeBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch)
|
void OverTimeBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch)
|
||||||
{
|
{
|
||||||
const auto originator = context->originator;
|
const auto originator = context->originator;
|
||||||
|
|
||||||
auto* entity = EntityManager::Instance()->GetEntity(originator);
|
auto* entity = EntityManager::Instance()->GetEntity(originator);
|
||||||
|
|
||||||
if (entity == nullptr)
|
if (entity == nullptr) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < m_NumIntervals; i++)
|
for (size_t i = 0; i < m_NumIntervals; i++)
|
||||||
{
|
{
|
||||||
entity->AddCallbackTimer((i + 1) * m_Delay, [originator, branch, this]() {
|
entity->AddCallbackTimer((i + 1) * m_Delay, [originator, branch, this]() {
|
||||||
auto* entity = EntityManager::Instance()->GetEntity(originator);
|
auto* entity = EntityManager::Instance()->GetEntity(originator);
|
||||||
|
|
||||||
if (entity == nullptr)
|
if (entity == nullptr) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* skillComponent = entity->GetComponent<SkillComponent>();
|
auto* skillComponent = entity->GetComponent<SkillComponent>();
|
||||||
|
|
||||||
if (skillComponent == nullptr)
|
if (skillComponent == nullptr) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
skillComponent->CalculateBehavior(0, m_Action->m_behaviorId, branch.target, true, true);
|
skillComponent->CalculateBehavior(m_Action, m_ActionBehaviorId, branch.target, true, true);
|
||||||
|
|
||||||
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
|
||||||
|
|
||||||
if (destroyableComponent == nullptr)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Special cases for inconsistent behavior.
|
|
||||||
*/
|
|
||||||
|
|
||||||
switch (m_behaviorId)
|
|
||||||
{
|
|
||||||
case 26253: // "Doc in a Box", heal up to 6 health and regen up to 18 armor.
|
|
||||||
destroyableComponent->Heal(1);
|
|
||||||
destroyableComponent->Repair(3);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,7 +38,12 @@ void OverTimeBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bi
|
|||||||
|
|
||||||
void OverTimeBehavior::Load()
|
void OverTimeBehavior::Load()
|
||||||
{
|
{
|
||||||
m_Action = GetAction("action");
|
m_Action = GetInt("action");
|
||||||
|
// Since m_Action is a skillID and not a behavior, get is correlated behaviorID.
|
||||||
|
|
||||||
|
CDSkillBehaviorTable* skillTable = CDClientManager::Instance()->GetTable<CDSkillBehaviorTable>("SkillBehavior");
|
||||||
|
m_ActionBehaviorId = skillTable->GetSkillByID(m_Action).behaviorID;
|
||||||
|
|
||||||
m_Delay = GetFloat("delay");
|
m_Delay = GetFloat("delay");
|
||||||
m_NumIntervals = GetInt("num_intervals");
|
m_NumIntervals = GetInt("num_intervals");
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
class OverTimeBehavior final : public Behavior
|
class OverTimeBehavior final : public Behavior
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Behavior* m_Action;
|
uint32_t m_Action;
|
||||||
|
uint32_t m_ActionBehaviorId;
|
||||||
float m_Delay;
|
float m_Delay;
|
||||||
int32_t m_NumIntervals;
|
int32_t m_NumIntervals;
|
||||||
|
|
||||||
|
@ -29,6 +29,8 @@ ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Com
|
|||||||
m_GravityScale = 1;
|
m_GravityScale = 1;
|
||||||
m_DirtyCheats = false;
|
m_DirtyCheats = false;
|
||||||
m_IgnoreMultipliers = false;
|
m_IgnoreMultipliers = false;
|
||||||
|
m_PickupRadius = 0.0f;
|
||||||
|
m_DirtyPickupRadiusScale = true;
|
||||||
|
|
||||||
if (entity->GetLOT() != 1) // Other physics entities we care about will be added by BaseCombatAI
|
if (entity->GetLOT() != 1) // Other physics entities we care about will be added by BaseCombatAI
|
||||||
return;
|
return;
|
||||||
@ -85,7 +87,13 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo
|
|||||||
m_DirtyCheats = false;
|
m_DirtyCheats = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
outBitStream->Write0();
|
outBitStream->Write(m_DirtyPickupRadiusScale);
|
||||||
|
if (m_DirtyPickupRadiusScale) {
|
||||||
|
outBitStream->Write(m_PickupRadius);
|
||||||
|
outBitStream->Write0(); //No clue what this is so im leaving it false.
|
||||||
|
m_DirtyPickupRadiusScale = false;
|
||||||
|
}
|
||||||
|
|
||||||
outBitStream->Write0();
|
outBitStream->Write0();
|
||||||
|
|
||||||
outBitStream->Write(m_DirtyPosition || bIsInitialUpdate);
|
outBitStream->Write(m_DirtyPosition || bIsInitialUpdate);
|
||||||
@ -231,3 +239,31 @@ void ControllablePhysicsComponent::SetDirtyVelocity(bool val) {
|
|||||||
void ControllablePhysicsComponent::SetDirtyAngularVelocity(bool val) {
|
void ControllablePhysicsComponent::SetDirtyAngularVelocity(bool val) {
|
||||||
m_DirtyAngularVelocity = val;
|
m_DirtyAngularVelocity = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ControllablePhysicsComponent::AddPickupRadiusScale(float value) {
|
||||||
|
m_ActivePickupRadiusScales.push_back(value);
|
||||||
|
if (value > m_PickupRadius) {
|
||||||
|
m_PickupRadius = value;
|
||||||
|
m_DirtyPickupRadiusScale = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllablePhysicsComponent::RemovePickupRadiusScale(float value) {
|
||||||
|
// Attempt to remove pickup radius from active radii
|
||||||
|
const auto pos = std::find(m_ActivePickupRadiusScales.begin(), m_ActivePickupRadiusScales.end(), 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.\n", value, m_ActivePickupRadiusScales.size());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalculate pickup radius since we removed one by now
|
||||||
|
m_PickupRadius = 0.0f;
|
||||||
|
m_DirtyPickupRadiusScale = 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);
|
||||||
|
}
|
||||||
|
@ -227,6 +227,24 @@ public:
|
|||||||
|
|
||||||
dpEntity* GetdpEntity() const { return m_dpEntity; }
|
dpEntity* GetdpEntity() const { return m_dpEntity; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I store this in a vector because if I have 2 separate pickup radii being applied to the player, I dont know which one is correctly active.
|
||||||
|
* This method adds the pickup radius to the vector of active radii and if its larger than the current one, is applied as the new pickup radius.
|
||||||
|
*/
|
||||||
|
void AddPickupRadiusScale(float value) ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the provided pickup radius scale from our list of buffs
|
||||||
|
* The recalculates what our pickup radius is.
|
||||||
|
*/
|
||||||
|
void RemovePickupRadiusScale(float value) ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The pickup radii of this component.
|
||||||
|
* @return All active radii scales for this component.
|
||||||
|
*/
|
||||||
|
std::vector<float> GetActivePickupRadiusScales() { return m_ActivePickupRadiusScales; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* The entity that owns this component
|
* The entity that owns this component
|
||||||
@ -322,6 +340,21 @@ private:
|
|||||||
* Whether this entity is static, making it unable to move
|
* Whether this entity is static, making it unable to move
|
||||||
*/
|
*/
|
||||||
bool m_Static;
|
bool m_Static;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the pickup scale is dirty.
|
||||||
|
*/
|
||||||
|
bool m_DirtyPickupRadiusScale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of pickup radius scales for this entity
|
||||||
|
*/
|
||||||
|
std::vector<float> m_ActivePickupRadiusScales;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The active pickup radius for this entity
|
||||||
|
*/
|
||||||
|
float m_PickupRadius;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONTROLLABLEPHYSICSCOMPONENT_H
|
#endif // CONTROLLABLEPHYSICSCOMPONENT_H
|
||||||
|
@ -593,7 +593,7 @@ void DestroyableComponent::Repair(const uint32_t armor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, bool echo)
|
void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32_t skillID, bool echo)
|
||||||
{
|
{
|
||||||
if (GetHealth() <= 0)
|
if (GetHealth() <= 0)
|
||||||
{
|
{
|
||||||
@ -677,11 +677,10 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, bool e
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Smash(source, eKillType::VIOLENT, u"", skillID);
|
||||||
Smash(source);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType)
|
void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType, uint32_t skillID)
|
||||||
{
|
{
|
||||||
if (m_iHealth > 0)
|
if (m_iHealth > 0)
|
||||||
{
|
{
|
||||||
@ -727,31 +726,20 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
|
|||||||
if (memberMissions == nullptr) continue;
|
if (memberMissions == nullptr) continue;
|
||||||
|
|
||||||
memberMissions->Progress(MissionTaskType::MISSION_TASK_TYPE_SMASH, m_Parent->GetLOT());
|
memberMissions->Progress(MissionTaskType::MISSION_TASK_TYPE_SMASH, m_Parent->GetLOT());
|
||||||
|
memberMissions->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, m_Parent->GetLOT(), skillID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SMASH, m_Parent->GetLOT());
|
missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SMASH, m_Parent->GetLOT());
|
||||||
|
missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, m_Parent->GetLOT(), skillID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto isPlayer = m_Parent->IsPlayer();
|
const auto isPlayer = m_Parent->IsPlayer();
|
||||||
|
|
||||||
GameMessages::SendDie(
|
GameMessages::SendDie(m_Parent, source, source, true, killType, deathType, 0, 0, 0, isPlayer, false, 1);
|
||||||
m_Parent,
|
|
||||||
source,
|
|
||||||
source,
|
|
||||||
true,
|
|
||||||
killType,
|
|
||||||
deathType,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
isPlayer,
|
|
||||||
false,
|
|
||||||
1
|
|
||||||
);
|
|
||||||
|
|
||||||
//NANI?!
|
//NANI?!
|
||||||
if (!isPlayer)
|
if (!isPlayer)
|
||||||
|
@ -377,17 +377,19 @@ public:
|
|||||||
* Attempt to damage this entity, handles everything from health and armor to absorption, immunity and callbacks.
|
* Attempt to damage this entity, handles everything from health and armor to absorption, immunity and callbacks.
|
||||||
* @param damage the damage to attempt to apply
|
* @param damage the damage to attempt to apply
|
||||||
* @param source the attacker that caused this damage
|
* @param source the attacker that caused this damage
|
||||||
|
* @param skillID the skill that damaged this entity
|
||||||
* @param echo whether or not to serialize the damage
|
* @param echo whether or not to serialize the damage
|
||||||
*/
|
*/
|
||||||
void Damage(uint32_t damage, LWOOBJID source, bool echo = true);
|
void Damage(uint32_t damage, LWOOBJID source, uint32_t skillID = 0, bool echo = true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Smashes this entity, notifying all clients
|
* Smashes this entity, notifying all clients
|
||||||
* @param source the source that smashed this entity
|
* @param source the source that smashed this entity
|
||||||
|
* @param skillID the skill that killed this entity
|
||||||
* @param killType the way this entity was killed, determines if a client animation is played
|
* @param killType the way this entity was killed, determines if a client animation is played
|
||||||
* @param deathType the animation to play when killed
|
* @param deathType the animation to play when killed
|
||||||
*/
|
*/
|
||||||
void Smash(LWOOBJID source, eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u"");
|
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
|
* Pushes a layer of immunity to this entity, making it immune for longer
|
||||||
|
@ -25,12 +25,14 @@ ProjectileSyncEntry::ProjectileSyncEntry()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t skillUid, RakNet::BitStream* bitStream, const LWOOBJID target)
|
bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t skillUid, RakNet::BitStream* bitStream, const LWOOBJID target, uint32_t skillID)
|
||||||
{
|
{
|
||||||
auto* context = new BehaviorContext(this->m_Parent->GetObjectID());
|
auto* context = new BehaviorContext(this->m_Parent->GetObjectID());
|
||||||
|
|
||||||
context->caster = m_Parent->GetObjectID();
|
context->caster = m_Parent->GetObjectID();
|
||||||
|
|
||||||
|
context->skillID = skillID;
|
||||||
|
|
||||||
this->m_managedBehaviors.insert_or_assign(skillUid, context);
|
this->m_managedBehaviors.insert_or_assign(skillUid, context);
|
||||||
|
|
||||||
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
||||||
|
@ -92,7 +92,7 @@ public:
|
|||||||
* @param bitStream the bitSteam given by the client to determine the behavior path
|
* @param bitStream the bitSteam given by the client to determine the behavior path
|
||||||
* @param target the explicit target of the skill
|
* @param target the explicit target of the skill
|
||||||
*/
|
*/
|
||||||
bool CastPlayerSkill(uint32_t behaviorId, uint32_t skillUid, RakNet::BitStream* bitStream, LWOOBJID target);
|
bool CastPlayerSkill(uint32_t behaviorId, uint32_t skillUid, RakNet::BitStream* bitStream, LWOOBJID target, uint32_t skillID = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Continues a player skill. Should only be called when the server receives a sync message from the client.
|
* Continues a player skill. Should only be called when the server receives a sync message from the client.
|
||||||
|
@ -1,88 +1,21 @@
|
|||||||
#include "VendorComponent.h"
|
#include "VendorComponent.h"
|
||||||
#include "Game.h"
|
|
||||||
#include "dServer.h"
|
|
||||||
|
|
||||||
#include <BitStream.h>
|
#include <BitStream.h>
|
||||||
|
|
||||||
|
#include "Game.h"
|
||||||
|
#include "dServer.h"
|
||||||
|
|
||||||
VendorComponent::VendorComponent(Entity* parent) : Component(parent) {
|
VendorComponent::VendorComponent(Entity* parent) : Component(parent) {
|
||||||
auto* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
|
SetupConstants();
|
||||||
auto* vendorComponentTable = CDClientManager::Instance()->GetTable<CDVendorComponentTable>("VendorComponent");
|
RefreshInventory(true);
|
||||||
auto* lootMatrixTable = CDClientManager::Instance()->GetTable<CDLootMatrixTable>("LootMatrix");
|
|
||||||
auto* lootTableTable = CDClientManager::Instance()->GetTable<CDLootTableTable>("LootTable");
|
|
||||||
|
|
||||||
int componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), COMPONENT_TYPE_VENDOR);
|
|
||||||
std::vector<CDVendorComponent> vendorComps = vendorComponentTable->Query([=](CDVendorComponent entry) { return (entry.id == componentID); });
|
|
||||||
if (vendorComps.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_BuyScalar = vendorComps[0].buyScalar;
|
|
||||||
m_SellScalar = vendorComps[0].sellScalar;
|
|
||||||
int lootMatrixID = vendorComps[0].LootMatrixIndex;
|
|
||||||
std::vector<CDLootMatrix> lootMatrices = lootMatrixTable->Query([=](CDLootMatrix entry) { return (entry.LootMatrixIndex == lootMatrixID); });
|
|
||||||
if (lootMatrices.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const auto& lootMatrix : lootMatrices) {
|
|
||||||
int lootTableID = lootMatrix.LootTableIndex;
|
|
||||||
std::vector<CDLootTable> vendorItems = lootTableTable->Query([=](CDLootTable entry) { return (entry.LootTableIndex == lootTableID); });
|
|
||||||
if (lootMatrix.maxToDrop == 0 || lootMatrix.minToDrop == 0) {
|
|
||||||
for (CDLootTable item : vendorItems) {
|
|
||||||
m_Inventory.insert({item.itemid, item.sortPriority});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
auto randomCount = GeneralUtils::GenerateRandomNumber<int32_t>(lootMatrix.minToDrop, lootMatrix.maxToDrop);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < randomCount; i++) {
|
|
||||||
if (vendorItems.empty()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto randomItemIndex = GeneralUtils::GenerateRandomNumber<int32_t>(0, vendorItems.size() - 1);
|
|
||||||
|
|
||||||
const auto& randomItem = vendorItems[randomItemIndex];
|
|
||||||
|
|
||||||
vendorItems.erase(vendorItems.begin() + randomItemIndex);
|
|
||||||
|
|
||||||
m_Inventory.insert({randomItem.itemid, randomItem.sortPriority});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Because I want a vendor to sell these cameras
|
|
||||||
if (parent->GetLOT() == 13569) {
|
|
||||||
auto randomCamera = GeneralUtils::GenerateRandomNumber<int32_t>(0, 2);
|
|
||||||
|
|
||||||
switch (randomCamera) {
|
|
||||||
case 0:
|
|
||||||
m_Inventory.insert({16253, 0}); //Grungagroid
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
m_Inventory.insert({16254, 0}); //Hipstabrick
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
m_Inventory.insert({16204, 0}); //Megabrixel snapshot
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Custom code for Max vanity NPC
|
|
||||||
if (parent->GetLOT() == 9749 && Game::server->GetZoneID() == 1201) {
|
|
||||||
m_Inventory.clear();
|
|
||||||
m_Inventory.insert({11909, 0}); //Top hat w frog
|
|
||||||
m_Inventory.insert({7785, 0}); //Flash bulb
|
|
||||||
m_Inventory.insert({12764, 0}); //Big fountain soda
|
|
||||||
m_Inventory.insert({12241, 0}); //Hot cocoa (from fb)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VendorComponent::~VendorComponent() = default;
|
VendorComponent::~VendorComponent() = default;
|
||||||
|
|
||||||
void VendorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
void VendorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||||
outBitStream->Write1();
|
outBitStream->Write1();
|
||||||
outBitStream->Write1(); // this bit is REQUIRED for vendor + mission multiinteract
|
outBitStream->Write1(); // Has standard items (Required for vendors with missions.)
|
||||||
outBitStream->Write(HasCraftingStation());
|
outBitStream->Write(HasCraftingStation()); // Has multi use items
|
||||||
}
|
}
|
||||||
|
|
||||||
void VendorComponent::OnUse(Entity* originator) {
|
void VendorComponent::OnUse(Entity* originator) {
|
||||||
@ -114,3 +47,85 @@ bool VendorComponent::HasCraftingStation() {
|
|||||||
// As far as we know, only Umami has a crafting station
|
// As far as we know, only Umami has a crafting station
|
||||||
return m_Parent->GetLOT() == 13800;
|
return m_Parent->GetLOT() == 13800;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VendorComponent::RefreshInventory(bool isCreation) {
|
||||||
|
//Custom code for Max vanity NPC
|
||||||
|
if (m_Parent->GetLOT() == 9749 && Game::server->GetZoneID() == 1201) {
|
||||||
|
if (!isCreation) return;
|
||||||
|
m_Inventory.insert({11909, 0}); //Top hat w frog
|
||||||
|
m_Inventory.insert({7785, 0}); //Flash bulb
|
||||||
|
m_Inventory.insert({12764, 0}); //Big fountain soda
|
||||||
|
m_Inventory.insert({12241, 0}); //Hot cocoa (from fb)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_Inventory.clear();
|
||||||
|
auto* lootMatrixTable = CDClientManager::Instance()->GetTable<CDLootMatrixTable>("LootMatrix");
|
||||||
|
std::vector<CDLootMatrix> lootMatrices = lootMatrixTable->Query([=](CDLootMatrix entry) { return (entry.LootMatrixIndex == m_LootMatrixID); });
|
||||||
|
|
||||||
|
if (lootMatrices.empty()) return;
|
||||||
|
// Done with lootMatrix table
|
||||||
|
|
||||||
|
auto* lootTableTable = CDClientManager::Instance()->GetTable<CDLootTableTable>("LootTable");
|
||||||
|
|
||||||
|
for (const auto& lootMatrix : lootMatrices) {
|
||||||
|
int lootTableID = lootMatrix.LootTableIndex;
|
||||||
|
std::vector<CDLootTable> vendorItems = lootTableTable->Query([=](CDLootTable entry) { return (entry.LootTableIndex == lootTableID); });
|
||||||
|
if (lootMatrix.maxToDrop == 0 || lootMatrix.minToDrop == 0) {
|
||||||
|
for (CDLootTable item : vendorItems) {
|
||||||
|
m_Inventory.insert({item.itemid, item.sortPriority});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto randomCount = GeneralUtils::GenerateRandomNumber<int32_t>(lootMatrix.minToDrop, lootMatrix.maxToDrop);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < randomCount; i++) {
|
||||||
|
if (vendorItems.empty()) break;
|
||||||
|
|
||||||
|
auto randomItemIndex = GeneralUtils::GenerateRandomNumber<int32_t>(0, vendorItems.size() - 1);
|
||||||
|
|
||||||
|
const auto& randomItem = vendorItems[randomItemIndex];
|
||||||
|
|
||||||
|
vendorItems.erase(vendorItems.begin() + randomItemIndex);
|
||||||
|
|
||||||
|
m_Inventory.insert({randomItem.itemid, randomItem.sortPriority});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Because I want a vendor to sell these cameras
|
||||||
|
if (m_Parent->GetLOT() == 13569) {
|
||||||
|
auto randomCamera = GeneralUtils::GenerateRandomNumber<int32_t>(0, 2);
|
||||||
|
|
||||||
|
switch (randomCamera) {
|
||||||
|
case 0:
|
||||||
|
m_Inventory.insert({16253, 0}); //Grungagroid
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
m_Inventory.insert({16254, 0}); //Hipstabrick
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
m_Inventory.insert({16204, 0}); //Megabrixel snapshot
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback timer to refresh this inventory.
|
||||||
|
m_Parent->AddCallbackTimer(m_RefreshTimeSeconds, [this]() {
|
||||||
|
RefreshInventory();
|
||||||
|
});
|
||||||
|
GameMessages::SendVendorStatusUpdate(m_Parent, UNASSIGNED_SYSTEM_ADDRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VendorComponent::SetupConstants() {
|
||||||
|
auto* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
|
||||||
|
int componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), COMPONENT_TYPE_VENDOR);
|
||||||
|
|
||||||
|
auto* vendorComponentTable = CDClientManager::Instance()->GetTable<CDVendorComponentTable>("VendorComponent");
|
||||||
|
std::vector<CDVendorComponent> vendorComps = vendorComponentTable->Query([=](CDVendorComponent entry) { return (entry.id == componentID); });
|
||||||
|
if (vendorComps.empty()) return;
|
||||||
|
m_BuyScalar = vendorComps[0].buyScalar;
|
||||||
|
m_SellScalar = vendorComps[0].sellScalar;
|
||||||
|
m_RefreshTimeSeconds = vendorComps[0].refreshTimeSeconds;
|
||||||
|
m_LootMatrixID = vendorComps[0].LootMatrixIndex;
|
||||||
|
}
|
@ -1,11 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
#ifndef VENDORCOMPONENT_H
|
#ifndef VENDORCOMPONENT_H
|
||||||
#define VENDORCOMPONENT_H
|
#define VENDORCOMPONENT_H
|
||||||
|
|
||||||
#include "RakNetTypes.h"
|
|
||||||
#include "Entity.h"
|
|
||||||
#include "GameMessages.h"
|
|
||||||
#include "CDClientManager.h"
|
#include "CDClientManager.h"
|
||||||
#include "Component.h"
|
#include "Component.h"
|
||||||
|
#include "Entity.h"
|
||||||
|
#include "GameMessages.h"
|
||||||
|
#include "RakNetTypes.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A component for vendor NPCs. A vendor sells items to the player.
|
* A component for vendor NPCs. A vendor sells items to the player.
|
||||||
@ -56,17 +57,36 @@ public:
|
|||||||
*/
|
*/
|
||||||
std::map<LOT, int>& GetInventory();
|
std::map<LOT, int>& GetInventory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the inventory of this vendor.
|
||||||
|
*/
|
||||||
|
void RefreshInventory(bool isCreation = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on startup of vendor to setup the variables for the component.
|
||||||
|
*/
|
||||||
|
void SetupConstants();
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* The buy scaler.
|
* The buy scalar.
|
||||||
*/
|
*/
|
||||||
float m_BuyScalar;
|
float m_BuyScalar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sell scaler.
|
* The sell scalar.
|
||||||
*/
|
*/
|
||||||
float m_SellScalar;
|
float m_SellScalar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The refresh time of this vendors' inventory.
|
||||||
|
*/
|
||||||
|
float m_RefreshTimeSeconds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loot matrix id of this vendor.
|
||||||
|
*/
|
||||||
|
uint32_t m_LootMatrixID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of items the vendor sells.
|
* The list of items the vendor sells.
|
||||||
*/
|
*/
|
||||||
|
@ -285,7 +285,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
|
|||||||
|
|
||||||
auto* skillComponent = entity->GetComponent<SkillComponent>();
|
auto* skillComponent = entity->GetComponent<SkillComponent>();
|
||||||
|
|
||||||
success = skillComponent->CastPlayerSkill(behaviorId, startSkill.uiSkillHandle, bs, startSkill.optionalTargetID);
|
success = skillComponent->CastPlayerSkill(behaviorId, startSkill.uiSkillHandle, bs, startSkill.optionalTargetID, startSkill.skillID);
|
||||||
|
|
||||||
if (success && entity->GetCharacter()) {
|
if (success && entity->GetCharacter()) {
|
||||||
DestroyableComponent* destComp = entity->GetComponent<DestroyableComponent>();
|
DestroyableComponent* destComp = entity->GetComponent<DestroyableComponent>();
|
||||||
|
@ -1252,8 +1252,7 @@ void GameMessages::SendVendorOpenWindow(Entity* entity, const SystemAddress& sys
|
|||||||
SEND_PACKET
|
SEND_PACKET
|
||||||
}
|
}
|
||||||
|
|
||||||
// ah yes, impl code in a send function, beautiful!
|
void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& sysAddr, bool bUpdateOnly) {
|
||||||
void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& sysAddr) {
|
|
||||||
CBITSTREAM
|
CBITSTREAM
|
||||||
CMSGHEADER
|
CMSGHEADER
|
||||||
|
|
||||||
@ -1265,7 +1264,7 @@ void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& s
|
|||||||
bitStream.Write(entity->GetObjectID());
|
bitStream.Write(entity->GetObjectID());
|
||||||
bitStream.Write(GAME_MSG::GAME_MSG_VENDOR_STATUS_UPDATE);
|
bitStream.Write(GAME_MSG::GAME_MSG_VENDOR_STATUS_UPDATE);
|
||||||
|
|
||||||
bitStream.Write(false);
|
bitStream.Write(bUpdateOnly);
|
||||||
bitStream.Write(static_cast<uint32_t>(vendorItems.size()));
|
bitStream.Write(static_cast<uint32_t>(vendorItems.size()));
|
||||||
|
|
||||||
for (std::pair<LOT, int> item : vendorItems) {
|
for (std::pair<LOT, int> item : vendorItems) {
|
||||||
@ -1273,6 +1272,7 @@ void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& s
|
|||||||
bitStream.Write(static_cast<int>(item.second));
|
bitStream.Write(static_cast<int>(item.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST
|
||||||
SEND_PACKET
|
SEND_PACKET
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ namespace GameMessages {
|
|||||||
void SendModularBuildEnd(Entity* entity);
|
void SendModularBuildEnd(Entity* entity);
|
||||||
|
|
||||||
void SendVendorOpenWindow(Entity* entity, const SystemAddress& sysAddr);
|
void SendVendorOpenWindow(Entity* entity, const SystemAddress& sysAddr);
|
||||||
void SendVendorStatusUpdate(Entity* entity, const SystemAddress& sysAddr);
|
void SendVendorStatusUpdate(Entity* entity, const SystemAddress& sysAddr, bool bUpdateOnly = false);
|
||||||
void SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr);
|
void SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr);
|
||||||
|
|
||||||
void SendRemoveItemFromInventory(Entity* entity, const SystemAddress& sysAddr, LWOOBJID iObjID, LOT templateID, int inventoryType, uint32_t stackCount, uint32_t stackRemaining);
|
void SendRemoveItemFromInventory(Entity* entity, const SystemAddress& sysAddr, LWOOBJID iObjID, LOT templateID, int inventoryType, uint32_t stackCount, uint32_t stackRemaining);
|
||||||
|
@ -102,6 +102,10 @@ int32_t Inventory::FindEmptySlot()
|
|||||||
{
|
{
|
||||||
newSize += 9u;
|
newSize += 9u;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newSize += 10u;
|
||||||
|
}
|
||||||
|
|
||||||
if (newSize > GetSize())
|
if (newSize > GetSize())
|
||||||
{
|
{
|
||||||
|
@ -326,10 +326,12 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string&
|
|||||||
|
|
||||||
case MissionTaskType::MISSION_TASK_TYPE_SKILL:
|
case MissionTaskType::MISSION_TASK_TYPE_SKILL:
|
||||||
{
|
{
|
||||||
if (!InParameters(value)) break;
|
// This is a complicated check because for some missions we need to check for the associate being in the parameters instead of the value being in the parameters.
|
||||||
|
if (associate == LWOOBJID_EMPTY && GetAllTargets().size() == 1 && GetAllTargets()[0] == -1) {
|
||||||
AddProgress(count);
|
if (InParameters(value)) AddProgress(count);
|
||||||
|
} else {
|
||||||
|
if (InParameters(associate) && InAllTargets(value)) AddProgress(count);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,6 +324,7 @@ enum GAME_MSG : unsigned short {
|
|||||||
GAME_MSG_ACTIVITY_STOP = 408,
|
GAME_MSG_ACTIVITY_STOP = 408,
|
||||||
GAME_MSG_SHOOTING_GALLERY_CLIENT_AIM_UPDATE = 409,
|
GAME_MSG_SHOOTING_GALLERY_CLIENT_AIM_UPDATE = 409,
|
||||||
GAME_MSG_SHOOTING_GALLERY_FIRE = 411,
|
GAME_MSG_SHOOTING_GALLERY_FIRE = 411,
|
||||||
|
GAME_MSG_REQUEST_VENDOR_STATUS_UPDATE = 416,
|
||||||
GAME_MSG_VENDOR_STATUS_UPDATE = 417,
|
GAME_MSG_VENDOR_STATUS_UPDATE = 417,
|
||||||
GAME_MSG_NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE = 425,
|
GAME_MSG_NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE = 425,
|
||||||
GAME_MSG_CONSUME_CLIENT_ITEM = 427,
|
GAME_MSG_CONSUME_CLIENT_ITEM = 427,
|
||||||
|
@ -49,7 +49,7 @@ void BaseEnemyApe::OnTimerDone(Entity *self, std::string timerName) {
|
|||||||
if (destroyableComponent != nullptr) {
|
if (destroyableComponent != nullptr) {
|
||||||
destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor() / timesStunned);
|
destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor() / timesStunned);
|
||||||
}
|
}
|
||||||
|
EntityManager::Instance()->SerializeEntity(self);
|
||||||
self->SetVar<uint32_t>(u"timesStunned", timesStunned + 1);
|
self->SetVar<uint32_t>(u"timesStunned", timesStunned + 1);
|
||||||
StunApe(self, false);
|
StunApe(self, false);
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ void NsConcertInstrument::EquipInstruments(Entity *self, Entity *player) {
|
|||||||
// Equip the left hand instrument
|
// Equip the left hand instrument
|
||||||
const auto leftInstrumentLot = instrumentLotLeft.find(GetInstrumentLot(self))->second;
|
const auto leftInstrumentLot = instrumentLotLeft.find(GetInstrumentLot(self))->second;
|
||||||
if (leftInstrumentLot != LOT_NULL) {
|
if (leftInstrumentLot != LOT_NULL) {
|
||||||
inventory->AddItem(leftInstrumentLot, 1, eLootSourceType::LOOT_SOURCE_ACTIVITY);
|
inventory->AddItem(leftInstrumentLot, 1, eLootSourceType::LOOT_SOURCE_NONE, TEMP_ITEMS, {}, LWOOBJID_EMPTY, false);
|
||||||
auto* leftInstrument = inventory->FindItemByLot(leftInstrumentLot, TEMP_ITEMS);
|
auto* leftInstrument = inventory->FindItemByLot(leftInstrumentLot, TEMP_ITEMS);
|
||||||
leftInstrument->Equip();
|
leftInstrument->Equip();
|
||||||
}
|
}
|
||||||
@ -203,7 +203,7 @@ void NsConcertInstrument::EquipInstruments(Entity *self, Entity *player) {
|
|||||||
// Equip the right hand instrument
|
// Equip the right hand instrument
|
||||||
const auto rightInstrumentLot = instrumentLotRight.find(GetInstrumentLot(self))->second;
|
const auto rightInstrumentLot = instrumentLotRight.find(GetInstrumentLot(self))->second;
|
||||||
if (rightInstrumentLot != LOT_NULL) {
|
if (rightInstrumentLot != LOT_NULL) {
|
||||||
inventory->AddItem(rightInstrumentLot, 1, eLootSourceType::LOOT_SOURCE_ACTIVITY);
|
inventory->AddItem(rightInstrumentLot, 1, eLootSourceType::LOOT_SOURCE_NONE, TEMP_ITEMS, {}, LWOOBJID_EMPTY, false);
|
||||||
auto* rightInstrument = inventory->FindItemByLot(rightInstrumentLot, TEMP_ITEMS);
|
auto* rightInstrument = inventory->FindItemByLot(rightInstrumentLot, TEMP_ITEMS);
|
||||||
rightInstrument->Equip();
|
rightInstrument->Equip();
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,11 @@ void NtParadoxPanelServer::OnUse(Entity* self, Entity* user)
|
|||||||
GameMessages::SendPlayAnimation(player, u"rebuild-celebrate");
|
GameMessages::SendPlayAnimation(player, u"rebuild-celebrate");
|
||||||
|
|
||||||
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SparkStop", 0, 0, player->GetObjectID(), "", player->GetSystemAddress());
|
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SparkStop", 0, 0, player->GetObjectID(), "", player->GetSystemAddress());
|
||||||
|
GameMessages::SendSetStunned(player->GetObjectID(), eStunState::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true);
|
||||||
self->SetVar(u"bActive", false);
|
self->SetVar(u"bActive", false);
|
||||||
});
|
});
|
||||||
|
GameMessages::SendPlayAnimation(user, u"nexus-powerpanel", 6.0f);
|
||||||
|
GameMessages::SendSetStunned(user->GetObjectID(), eStunState::PUSH, user->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user