mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-08-09 20:24:16 +00:00
Refactor damage calculations and add additional modifiers
This commit is contained in:
@@ -556,7 +556,7 @@ void DestroyableComponent::Repair(const uint32_t armor) {
|
||||
}
|
||||
|
||||
|
||||
void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32_t skillID, bool echo) {
|
||||
void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32_t skillID, bool echo, bool isDamageOverTime) {
|
||||
if (GetHealth() <= 0) {
|
||||
return;
|
||||
}
|
||||
@@ -572,7 +572,9 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
|
||||
return;
|
||||
}
|
||||
|
||||
OnDamageCalculation(m_Parent, source, skillID, damage);
|
||||
if (!isDamageOverTime) {
|
||||
OnDamageCalculation(m_Parent, source, skillID, damage);
|
||||
}
|
||||
|
||||
// If this entity has damage reduction, reduce the damage to a minimum of 1
|
||||
if (m_DamageReduction > 0 && damage > 0) {
|
||||
@@ -641,6 +643,42 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
|
||||
cb(attacker);
|
||||
}
|
||||
|
||||
std::stringstream damageUIMessage;
|
||||
|
||||
auto damagedPosition = m_Parent->GetPosition();
|
||||
|
||||
// Add a slight random offset to the damage position
|
||||
damagedPosition.x += (rand() % 10 - 5) / 5.0f;
|
||||
damagedPosition.y += (rand() % 10 - 5) / 5.0f;
|
||||
damagedPosition.z += (rand() % 10 - 5) / 5.0f;
|
||||
|
||||
int colorR = 255;
|
||||
int colorG = 255;
|
||||
int colorB = 255;
|
||||
int colorA = 0;
|
||||
|
||||
if (m_Parent->IsPlayer()) {
|
||||
// Make the damage red
|
||||
colorR = 0;
|
||||
colorG = 255;
|
||||
colorB = 0;
|
||||
colorA = 0;
|
||||
}
|
||||
|
||||
const auto damageText = damage != 0 ? std::to_string(damage) : "Miss";
|
||||
|
||||
damageUIMessage << 0.0825 << ";" << 0.12 << ";" << damagedPosition.x << ";" << damagedPosition.y + 4.5f << ";" << damagedPosition.z << ";" << 0.1 << ";";
|
||||
damageUIMessage << 200 << ";" << 200 << ";" << 0.5 << ";" << 1.0 << ";" << damageText << ";" << 4 << ";" << 4 << ";" << colorR << ";" << colorG << ";" << colorB << ";";
|
||||
damageUIMessage << colorA;
|
||||
|
||||
const auto damageUIStr = damageUIMessage.str();
|
||||
|
||||
if (m_Parent->IsPlayer()) {
|
||||
m_Parent->SetNetworkVar<std::string>(u"renderText", damageUIStr, UNASSIGNED_SYSTEM_ADDRESS);
|
||||
} else if (attacker->IsPlayer()) {
|
||||
attacker->SetNetworkVar<std::string>(u"renderText", damageUIStr, UNASSIGNED_SYSTEM_ADDRESS);
|
||||
}
|
||||
|
||||
if (health != 0) {
|
||||
auto* combatComponent = m_Parent->GetComponent<BaseCombatAIComponent>();
|
||||
|
||||
|
@@ -384,8 +384,9 @@ public:
|
||||
* @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 isDamageOverTime whether or not this damage is over time
|
||||
*/
|
||||
void Damage(uint32_t damage, LWOOBJID source, uint32_t skillID = 0, bool echo = true);
|
||||
void Damage(uint32_t damage, LWOOBJID source, uint32_t skillID = 0, bool echo = true, bool isDamageOverTime = false);
|
||||
|
||||
/**
|
||||
* Smashes this entity, notifying all clients
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#include "InventoryComponent.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "Entity.h"
|
||||
#include "Item.h"
|
||||
@@ -43,6 +44,7 @@ Observable<InventoryComponent*, Item*> InventoryComponent::OnItemDestroyed;
|
||||
Observable<InventoryComponent*, Item*> InventoryComponent::OnItemEquipped;
|
||||
Observable<InventoryComponent*, Item*> InventoryComponent::OnItemUnequipped;
|
||||
Observable<InventoryComponent*, Item*> InventoryComponent::OnItemLoaded;
|
||||
Observable<InventoryComponent*, Item*> InventoryComponent::OnCountChanged;
|
||||
|
||||
InventoryComponent::InventoryComponent(Entity* parent) : Component(parent) {
|
||||
this->m_Dirty = true;
|
||||
@@ -1131,27 +1133,13 @@ void InventoryComponent::AddItemSkills(const LOT lot) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto skill = FindSkill(lot);
|
||||
if (m_PrimarySkill != 0) {
|
||||
GameMessages::SendRemoveSkill(m_Parent, m_PrimarySkill);
|
||||
}
|
||||
|
||||
const auto index = m_Skills.find(slot);
|
||||
m_PrimarySkill = FindSkill(lot);
|
||||
|
||||
if (index != m_Skills.end()) {
|
||||
const auto old = index->second;
|
||||
|
||||
if (!old.empty()) {
|
||||
const auto firstElem = *old.begin();
|
||||
|
||||
GameMessages::SendRemoveSkill(m_Parent, firstElem);
|
||||
}
|
||||
}
|
||||
|
||||
m_Skills.erase(slot);
|
||||
|
||||
if (skill != 0) {
|
||||
m_Skills.insert_or_assign(slot, std::set<uint32_t>{ skill });
|
||||
|
||||
GameMessages::SendAddSkill(m_Parent, skill, slot);
|
||||
}
|
||||
GameMessages::SendAddSkill(m_Parent, m_PrimarySkill, slot);
|
||||
}
|
||||
|
||||
void InventoryComponent::RemoveItemSkills(const LOT lot) {
|
||||
@@ -1163,27 +1151,11 @@ void InventoryComponent::RemoveItemSkills(const LOT lot) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto index = m_Skills.find(slot);
|
||||
GameMessages::SendRemoveSkill(m_Parent, m_PrimarySkill);
|
||||
|
||||
if (index == m_Skills.end()) {
|
||||
return;
|
||||
}
|
||||
m_PrimarySkill = 1;
|
||||
|
||||
const auto old = index->second;
|
||||
|
||||
if (!old.empty()) {
|
||||
const auto firstElem = *old.begin();
|
||||
|
||||
GameMessages::SendRemoveSkill(m_Parent, firstElem);
|
||||
}
|
||||
|
||||
m_Skills.erase(slot);
|
||||
|
||||
if (slot == BehaviorSlot::Primary) {
|
||||
m_Skills.insert_or_assign(BehaviorSlot::Primary, std::set<uint32_t>{ 1 });
|
||||
|
||||
GameMessages::SendAddSkill(m_Parent, 1, BehaviorSlot::Primary);
|
||||
}
|
||||
GameMessages::SendAddSkill(m_Parent, m_PrimarySkill, BehaviorSlot::Primary);
|
||||
}
|
||||
|
||||
void InventoryComponent::TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target) {
|
||||
@@ -1360,6 +1332,71 @@ void InventoryComponent::SetNPCItems(const std::vector<LOT>& items) {
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}
|
||||
|
||||
bool InventoryComponent::AddSkill(uint32_t skillId) {
|
||||
if (std::find(m_Skills.begin(), m_Skills.end(), skillId) != m_Skills.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Skills.push_back(skillId);
|
||||
|
||||
UpdateSkills();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InventoryComponent::RemoveSkill(uint32_t skillId) {
|
||||
const auto index = std::find(m_Skills.begin(), m_Skills.end(), skillId);
|
||||
|
||||
if (index == m_Skills.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Skills.erase(index);
|
||||
|
||||
UpdateSkills();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void InventoryComponent::UpdateSkills() {
|
||||
// There are two skills active at the same time. If the rotation index is greater than the amount of skills / 2, set it to the max number is can be.
|
||||
// This is to prevent the rotation index from going out of bounds.
|
||||
if (m_SkillRotationIndex * 2 >= m_Skills.size()) {
|
||||
m_SkillRotationIndex = 0;
|
||||
}
|
||||
|
||||
const auto startIndex = m_SkillRotationIndex * 2;
|
||||
|
||||
const auto activeSkillA = m_Skills.size() > startIndex ? m_Skills[startIndex] : 0;
|
||||
const auto activeSkillB = m_Skills.size() > startIndex + 1 ? m_Skills[startIndex + 1] : 0;
|
||||
|
||||
std::cout << "Skill rotation index: " << m_SkillRotationIndex << " Active skills: " << activeSkillA << " " << activeSkillB << "\n";
|
||||
|
||||
GameMessages::SendRemoveSkill(m_Parent, m_ActiveSkills.first);
|
||||
GameMessages::SendRemoveSkill(m_Parent, m_ActiveSkills.second);
|
||||
|
||||
m_ActiveSkills = { activeSkillA, activeSkillB };
|
||||
|
||||
if (activeSkillA != 0) {
|
||||
GameMessages::SendAddSkill(m_Parent, activeSkillA, BehaviorSlot::Head);
|
||||
}
|
||||
|
||||
if (activeSkillB != 0) {
|
||||
GameMessages::SendAddSkill(m_Parent, activeSkillB, BehaviorSlot::Offhand);
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryComponent::RotateSkills() {
|
||||
m_SkillRotationIndex++;
|
||||
|
||||
if (m_SkillRotationIndex * 2 >= m_Skills.size()) {
|
||||
m_SkillRotationIndex = 0;
|
||||
}
|
||||
|
||||
UpdateSkills();
|
||||
}
|
||||
|
||||
InventoryComponent::~InventoryComponent() {
|
||||
for (const auto& inventory : m_Inventories) {
|
||||
delete inventory.second;
|
||||
@@ -1614,60 +1651,4 @@ void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument& document) {
|
||||
}
|
||||
|
||||
|
||||
bool InventoryComponent::SetSkill(int32_t slot, uint32_t skillId) {
|
||||
BehaviorSlot behaviorSlot = BehaviorSlot::Invalid;
|
||||
if (slot == 1) behaviorSlot = BehaviorSlot::Primary;
|
||||
else if (slot == 2) behaviorSlot = BehaviorSlot::Offhand;
|
||||
else if (slot == 3) behaviorSlot = BehaviorSlot::Neck;
|
||||
else if (slot == 4) behaviorSlot = BehaviorSlot::Head;
|
||||
else if (slot == 5) behaviorSlot = BehaviorSlot::Consumable;
|
||||
else return false;
|
||||
return SetSkill(behaviorSlot, skillId);
|
||||
}
|
||||
|
||||
bool InventoryComponent::SetSkill(BehaviorSlot slot, uint32_t skillId) {
|
||||
if (skillId == 0) return false;
|
||||
const auto index = m_Skills.find(slot);
|
||||
if (index == m_Skills.end()) {
|
||||
m_Skills.insert_or_assign(slot, std::set<uint32_t>{ skillId });
|
||||
} else {
|
||||
auto& existing = index->second;
|
||||
existing.insert(skillId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InventoryComponent::UnsetSkill(uint32_t skillId) {
|
||||
for (auto& pair : m_Skills) {
|
||||
auto& skills = pair.second;
|
||||
skills.erase(skillId);
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryComponent::SetSkill(uint32_t skillId) {
|
||||
UnsetSkill(skillId);
|
||||
|
||||
const auto& slotA = m_Skills.find(BehaviorSlot::Head);
|
||||
const auto& slotB = m_Skills.find(BehaviorSlot::Neck);
|
||||
const auto& slotC = m_Skills.find(BehaviorSlot::Offhand);
|
||||
|
||||
// Pick the first one which has less than 3 skills
|
||||
std::set<uint32_t>* slot = nullptr;
|
||||
|
||||
if (slotA == m_Skills.end() || slotA->second.size() < 3) {
|
||||
slot = &m_Skills[BehaviorSlot::Head];
|
||||
} else if (slotB == m_Skills.end() || slotB->second.size() < 3) {
|
||||
slot = &m_Skills[BehaviorSlot::Neck];
|
||||
} else if (slotC == m_Skills.end() || slotC->second.size() < 3) {
|
||||
slot = &m_Skills[BehaviorSlot::Offhand];
|
||||
}
|
||||
|
||||
if (slot == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
slot->insert(skillId);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -368,12 +368,14 @@ public:
|
||||
*/
|
||||
void UnequipScripts(Item* unequippedItem);
|
||||
|
||||
const std::map<BehaviorSlot, std::set<uint32_t>>& GetSkills(){ return m_Skills; };
|
||||
uint32_t GetPrimarySkill() const { return m_PrimarySkill; }
|
||||
|
||||
bool SetSkill(int32_t slot, uint32_t skillId);
|
||||
bool SetSkill(BehaviorSlot slot, uint32_t skillId);
|
||||
void UnsetSkill(uint32_t skillId);
|
||||
void SetSkill(uint32_t skillId);
|
||||
const std::vector<uint32_t>& GetSkills(){ return m_Skills; };
|
||||
|
||||
bool AddSkill(uint32_t skillId);
|
||||
bool RemoveSkill(uint32_t skillId);
|
||||
void RotateSkills();
|
||||
void UpdateSkills();
|
||||
|
||||
~InventoryComponent() override;
|
||||
|
||||
@@ -382,6 +384,7 @@ public:
|
||||
static Observable<InventoryComponent*, Item*> OnItemEquipped;
|
||||
static Observable<InventoryComponent*, Item*> OnItemUnequipped;
|
||||
static Observable<InventoryComponent*, Item*> OnItemLoaded;
|
||||
static Observable<InventoryComponent*, Item*> OnCountChanged;
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -391,10 +394,16 @@ private:
|
||||
|
||||
std::map<BehaviorSlot, uint32_t> m_ActivatorSkills;
|
||||
|
||||
uint32_t m_PrimarySkill = 0;
|
||||
|
||||
/**
|
||||
* The skills that this entity currently has active
|
||||
*/
|
||||
std::map<BehaviorSlot, std::set<uint32_t>> m_Skills;
|
||||
std::vector<uint32_t> m_Skills;
|
||||
|
||||
std::pair<uint32_t, uint32_t> m_ActiveSkills;
|
||||
|
||||
uint32_t m_SkillRotationIndex = 0;
|
||||
|
||||
/**
|
||||
* The pets this entity has, mapped by object ID and pet info
|
||||
|
Reference in New Issue
Block a user