mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-12-23 05:53:34 +00:00
Added upgrades
This commit is contained in:
parent
d5b2278dc5
commit
364bcf822a
@ -7,6 +7,9 @@
|
|||||||
#include <InventoryComponent.h>
|
#include <InventoryComponent.h>
|
||||||
#include <BaseCombatAIComponent.h>
|
#include <BaseCombatAIComponent.h>
|
||||||
#include <TeamManager.h>
|
#include <TeamManager.h>
|
||||||
|
#include <Item.h>
|
||||||
|
|
||||||
|
using namespace nejlika;
|
||||||
|
|
||||||
float nejlika::AdditionalEntityData::CalculateModifier(ModifierType type, ModifierOperator op, bool resistance) const
|
float nejlika::AdditionalEntityData::CalculateModifier(ModifierType type, ModifierOperator op, bool resistance) const
|
||||||
{
|
{
|
||||||
@ -86,9 +89,27 @@ float nejlika::AdditionalEntityData::CalculateModifier(ModifierType type, std::v
|
|||||||
|
|
||||||
float multiplicative = CalculateModifier(type, additionalModifiers, ModifierOperator::Multiplicative, false);
|
float multiplicative = CalculateModifier(type, additionalModifiers, ModifierOperator::Multiplicative, false);
|
||||||
|
|
||||||
std::cout << "Scaler: " << scaler << " Additive: " << additive << " Multiplicative: " << multiplicative << std::endl;
|
static const std::unordered_set<ModifierType> damageTypes = {
|
||||||
|
ModifierType::Slashing,
|
||||||
|
ModifierType::Piercing,
|
||||||
|
ModifierType::Bludgeoning,
|
||||||
|
ModifierType::Fire,
|
||||||
|
ModifierType::Cold,
|
||||||
|
ModifierType::Lightning,
|
||||||
|
ModifierType::Corruption,
|
||||||
|
ModifierType::Psychic
|
||||||
|
};
|
||||||
|
|
||||||
return (scaler + additive) * (1 + multiplicative / 100);
|
if (damageTypes.contains(type)) {
|
||||||
|
additive += CalculateModifier(ModifierType::Damage, additionalModifiers, ModifierOperator::Additive, false);
|
||||||
|
multiplicative += CalculateModifier(ModifierType::Damage, additionalModifiers, ModifierOperator::Multiplicative, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
float total = (scaler + additive) * (1 + multiplicative / 100);
|
||||||
|
|
||||||
|
std::cout << "Scaler: " << scaler << " Additive: " << additive << " Multiplicative: " << multiplicative << " Total: " << total << std::endl;
|
||||||
|
|
||||||
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
float nejlika::AdditionalEntityData::CalculateResistance(ModifierType type) const
|
float nejlika::AdditionalEntityData::CalculateResistance(ModifierType type) const
|
||||||
@ -96,6 +117,44 @@ float nejlika::AdditionalEntityData::CalculateResistance(ModifierType type) cons
|
|||||||
return CalculateModifier(type, ModifierOperator::Multiplicative, true);
|
return CalculateModifier(type, ModifierOperator::Multiplicative, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<ModifierInstance> nejlika::AdditionalEntityData::TriggerUpgradeItems(UpgradeTriggerType triggerType) {
|
||||||
|
auto* entity = Game::entityManager->GetEntity(id);
|
||||||
|
|
||||||
|
if (entity == nullptr) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* inventoryComponent = entity->GetComponent<InventoryComponent>();
|
||||||
|
|
||||||
|
if (inventoryComponent == nullptr) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ModifierInstance> result;
|
||||||
|
|
||||||
|
for (const auto& itemID : upgradeItems) {
|
||||||
|
auto* item = inventoryComponent->FindItemById(itemID);
|
||||||
|
|
||||||
|
if (item == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto upgradeDataOpt = NejlikaData::GetUpgradeTemplate(item->GetLot());
|
||||||
|
|
||||||
|
if (!upgradeDataOpt.has_value()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& upgradeData = *upgradeDataOpt.value();
|
||||||
|
|
||||||
|
const auto modifiers = upgradeData.Trigger(item->GetCount(), triggerType, id);
|
||||||
|
|
||||||
|
result.insert(result.end(), modifiers.begin(), modifiers.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void nejlika::AdditionalEntityData::RollStandardModifiers(int32_t level) {
|
void nejlika::AdditionalEntityData::RollStandardModifiers(int32_t level) {
|
||||||
standardModifiers.clear();
|
standardModifiers.clear();
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
|
|
||||||
#include "ModifierInstance.h"
|
#include "ModifierInstance.h"
|
||||||
#include "EntityTemplate.h"
|
#include "EntityTemplate.h"
|
||||||
|
#include "UpgradeTriggerType.h"
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace nejlika
|
namespace nejlika
|
||||||
{
|
{
|
||||||
@ -40,6 +43,14 @@ public:
|
|||||||
|
|
||||||
LOT GetLOT() const { return lot; }
|
LOT GetLOT() const { return lot; }
|
||||||
|
|
||||||
|
const std::unordered_set<LWOOBJID>& GetUpgradeItems() const { return upgradeItems; }
|
||||||
|
|
||||||
|
void AddUpgradeItem(LWOOBJID id) { upgradeItems.insert(id); }
|
||||||
|
|
||||||
|
void RemoveUpgradeItem(LWOOBJID id) { upgradeItems.erase(id); }
|
||||||
|
|
||||||
|
std::vector<ModifierInstance> TriggerUpgradeItems(UpgradeTriggerType triggerType);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void RollStandardModifiers(int32_t level);
|
void RollStandardModifiers(int32_t level);
|
||||||
|
|
||||||
@ -47,6 +58,7 @@ private:
|
|||||||
|
|
||||||
std::vector<ModifierInstance> standardModifiers;
|
std::vector<ModifierInstance> standardModifiers;
|
||||||
std::vector<ModifierInstance> activeModifiers;
|
std::vector<ModifierInstance> activeModifiers;
|
||||||
|
std::unordered_set<LWOOBJID> upgradeItems;
|
||||||
|
|
||||||
LWOOBJID id;
|
LWOOBJID id;
|
||||||
LOT lot;
|
LOT lot;
|
||||||
|
@ -19,6 +19,8 @@ set(DGAME_SOURCES "Character.cpp"
|
|||||||
"EntityTemplate.cpp"
|
"EntityTemplate.cpp"
|
||||||
"AdditionalEntityData.cpp"
|
"AdditionalEntityData.cpp"
|
||||||
"NejlikaHooks.cpp"
|
"NejlikaHooks.cpp"
|
||||||
|
"UpgradeTemplate.cpp"
|
||||||
|
"UpgradeEffect.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
|
@ -3,8 +3,25 @@
|
|||||||
nejlika::ModifierScale::ModifierScale(const nlohmann::json & json)
|
nejlika::ModifierScale::ModifierScale(const nlohmann::json & json)
|
||||||
{
|
{
|
||||||
level = json["level"].get<int32_t>();
|
level = json["level"].get<int32_t>();
|
||||||
min = json["min"].get<float>();
|
|
||||||
max = json["max"].get<float>();
|
if (json.contains("min")) {
|
||||||
|
min = json["min"].get<float>();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
min = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.contains("max")) {
|
||||||
|
max = json["max"].get<float>();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
max = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.contains("value")) {
|
||||||
|
min = json["value"].get<float>();
|
||||||
|
max = json["value"].get<float>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nlohmann::json nejlika::ModifierScale::ToJson() const
|
nlohmann::json nejlika::ModifierScale::ToJson() const
|
||||||
|
@ -26,6 +26,8 @@ enum class ModifierType : uint8_t
|
|||||||
|
|
||||||
Psychic,
|
Psychic,
|
||||||
|
|
||||||
|
Damage,
|
||||||
|
|
||||||
Invalid
|
Invalid
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@ std::unordered_map<LWOOBJID, nejlika::AdditionalEntityData> additionalEntityData
|
|||||||
|
|
||||||
std::unordered_map<LOT, nejlika::EntityTemplate> entityTemplates;
|
std::unordered_map<LOT, nejlika::EntityTemplate> entityTemplates;
|
||||||
|
|
||||||
|
std::unordered_map<LOT, nejlika::UpgradeTemplate> upgradeTemplates;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map<ModifierNameType,std::vector<ModifierNameTemplate>>& nejlika::NejlikaData::GetModifierNameTemplates()
|
const std::unordered_map<ModifierNameType,std::vector<ModifierNameTemplate>>& nejlika::NejlikaData::GetModifierNameTemplates()
|
||||||
@ -69,6 +71,16 @@ const std::optional<EntityTemplate*> nejlika::NejlikaData::GetEntityTemplate(LOT
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::optional<UpgradeTemplate*> nejlika::NejlikaData::GetUpgradeTemplate(LOT lot) {
|
||||||
|
const auto& it = upgradeTemplates.find(lot);
|
||||||
|
|
||||||
|
if (it != upgradeTemplates.end()) {
|
||||||
|
return std::optional<UpgradeTemplate*>(&it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
void nejlika::NejlikaData::SetAdditionalItemData(LWOOBJID id, AdditionalItemData data) {
|
void nejlika::NejlikaData::SetAdditionalItemData(LWOOBJID id, AdditionalItemData data) {
|
||||||
additionalItemData[id] = data;
|
additionalItemData[id] = data;
|
||||||
}
|
}
|
||||||
@ -147,5 +159,17 @@ void nejlika::NejlikaData::LoadNejlikaData()
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG("Loaded %d entity templates", entityTemplates.size());
|
LOG("Loaded %d entity templates", entityTemplates.size());
|
||||||
|
|
||||||
|
if (json.contains("upgrade-templates"))
|
||||||
|
{
|
||||||
|
const auto& upgradeTemplatesArray = json["upgrade-templates"];
|
||||||
|
|
||||||
|
for (const auto& value : upgradeTemplatesArray)
|
||||||
|
{
|
||||||
|
auto upgradeTemplate = UpgradeTemplate(value);
|
||||||
|
|
||||||
|
upgradeTemplates[upgradeTemplate.GetLot()] = upgradeTemplate;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "EntityTemplate.h"
|
#include "EntityTemplate.h"
|
||||||
#include "AdditionalItemData.h"
|
#include "AdditionalItemData.h"
|
||||||
#include "AdditionalEntityData.h"
|
#include "AdditionalEntityData.h"
|
||||||
|
#include "UpgradeTemplate.h"
|
||||||
|
|
||||||
namespace nejlika::NejlikaData
|
namespace nejlika::NejlikaData
|
||||||
{
|
{
|
||||||
@ -21,6 +22,8 @@ const std::optional<AdditionalEntityData*> GetAdditionalEntityData(LWOOBJID id);
|
|||||||
|
|
||||||
const std::optional<EntityTemplate*> GetEntityTemplate(LOT lot);
|
const std::optional<EntityTemplate*> GetEntityTemplate(LOT lot);
|
||||||
|
|
||||||
|
const std::optional<UpgradeTemplate*> GetUpgradeTemplate(LOT lot);
|
||||||
|
|
||||||
void SetAdditionalItemData(LWOOBJID id, AdditionalItemData data);
|
void SetAdditionalItemData(LWOOBJID id, AdditionalItemData data);
|
||||||
|
|
||||||
void SetAdditionalEntityData(LWOOBJID id, AdditionalEntityData data);
|
void SetAdditionalEntityData(LWOOBJID id, AdditionalEntityData data);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <PlayerManager.h>
|
#include <PlayerManager.h>
|
||||||
#include <eGameMessageType.h>
|
#include <eGameMessageType.h>
|
||||||
#include <dServer.h>
|
#include <dServer.h>
|
||||||
|
#include <Item.h>
|
||||||
|
|
||||||
#include "NejlikaData.h"
|
#include "NejlikaData.h"
|
||||||
|
|
||||||
@ -39,6 +40,7 @@ void nejlika::NejlikaHooks::InstallHooks()
|
|||||||
InventoryComponent::OnItemCreated += [](InventoryComponent* component, Item* item) {
|
InventoryComponent::OnItemCreated += [](InventoryComponent* component, Item* item) {
|
||||||
const auto& itemType = static_cast<eItemType>(item->GetInfo().itemType);
|
const auto& itemType = static_cast<eItemType>(item->GetInfo().itemType);
|
||||||
|
|
||||||
|
/*
|
||||||
static const std::unordered_set<eItemType> listOfHandledItems {
|
static const std::unordered_set<eItemType> listOfHandledItems {
|
||||||
eItemType::HAT,
|
eItemType::HAT,
|
||||||
eItemType::CHEST,
|
eItemType::CHEST,
|
||||||
@ -51,7 +53,9 @@ void nejlika::NejlikaHooks::InstallHooks()
|
|||||||
if (listOfHandledItems.find(itemType) == listOfHandledItems.end()) {
|
if (listOfHandledItems.find(itemType) == listOfHandledItems.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// No to the Thinking Hat
|
||||||
if (item->GetLot() == 6086) {
|
if (item->GetLot() == 6086) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -69,6 +73,24 @@ void nejlika::NejlikaHooks::InstallHooks()
|
|||||||
additionalData.RollModifiers(item, levelProgressionComponent->GetLevel());
|
additionalData.RollModifiers(item, levelProgressionComponent->GetLevel());
|
||||||
|
|
||||||
SetAdditionalItemData(item->GetId(), additionalData);
|
SetAdditionalItemData(item->GetId(), additionalData);
|
||||||
|
|
||||||
|
auto entityDataOpt = GetAdditionalEntityData(component->GetParent()->GetObjectID());
|
||||||
|
|
||||||
|
if (!entityDataOpt.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& entityData = *entityDataOpt.value();
|
||||||
|
|
||||||
|
auto upgradeTemplateOpt = GetUpgradeTemplate(item->GetLot());
|
||||||
|
|
||||||
|
if (!upgradeTemplateOpt.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& upgradeTemplate = *upgradeTemplateOpt.value();
|
||||||
|
|
||||||
|
entityData.AddUpgradeItem(item->GetId());
|
||||||
};
|
};
|
||||||
|
|
||||||
EntityManager::OnEntityCreated += [](Entity* entity) {
|
EntityManager::OnEntityCreated += [](Entity* entity) {
|
||||||
@ -89,6 +111,29 @@ void nejlika::NejlikaHooks::InstallHooks()
|
|||||||
auto& additionalData = *additionalDataOpt.value();
|
auto& additionalData = *additionalDataOpt.value();
|
||||||
|
|
||||||
additionalData.ApplyToEntity();
|
additionalData.ApplyToEntity();
|
||||||
|
|
||||||
|
auto* inventoryComponent = entity->GetComponent<InventoryComponent>();
|
||||||
|
|
||||||
|
if (!inventoryComponent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through all items and check if they are upgrade items
|
||||||
|
const auto& inventories = inventoryComponent->GetInventories();
|
||||||
|
|
||||||
|
for (const auto& [type, inventory] : inventories) {
|
||||||
|
for (const auto& [id, item] : inventory->GetItems()) {
|
||||||
|
const auto upgradeTemplateOpt = GetUpgradeTemplate(item->GetLot());
|
||||||
|
|
||||||
|
if (!upgradeTemplateOpt.has_value()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& upgradeTemplate = *upgradeTemplateOpt.value();
|
||||||
|
|
||||||
|
additionalData.AddUpgradeItem(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
EntityManager::OnEntityDestroyed += [](Entity* entity) {
|
EntityManager::OnEntityDestroyed += [](Entity* entity) {
|
||||||
@ -101,6 +146,38 @@ void nejlika::NejlikaHooks::InstallHooks()
|
|||||||
|
|
||||||
InventoryComponent::OnItemDestroyed += [](InventoryComponent* component, Item* item) {
|
InventoryComponent::OnItemDestroyed += [](InventoryComponent* component, Item* item) {
|
||||||
UnsetAdditionalItemData(item->GetId());
|
UnsetAdditionalItemData(item->GetId());
|
||||||
|
|
||||||
|
auto entityDataOpt = GetAdditionalEntityData(component->GetParent()->GetObjectID());
|
||||||
|
|
||||||
|
if (!entityDataOpt.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& entityData = *entityDataOpt.value();
|
||||||
|
|
||||||
|
entityData.RemoveUpgradeItem(item->GetId());
|
||||||
|
};
|
||||||
|
|
||||||
|
LevelProgressionComponent::OnLevelUp += [](LevelProgressionComponent* component) {
|
||||||
|
auto* parent = component->GetParent();
|
||||||
|
|
||||||
|
auto entityDataOpt = GetAdditionalEntityData(parent->GetObjectID());
|
||||||
|
|
||||||
|
if (!entityDataOpt.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& entityData = *entityDataOpt.value();
|
||||||
|
|
||||||
|
entityData.ApplyToEntity();
|
||||||
|
|
||||||
|
auto* inventoryComponent = parent->GetComponent<InventoryComponent>();
|
||||||
|
|
||||||
|
if (!inventoryComponent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inventoryComponent->AddItem(2097253, 1, eLootSourceType::LEVEL_REWARD);
|
||||||
};
|
};
|
||||||
|
|
||||||
InventoryComponent::OnItemEquipped += [](InventoryComponent* component, Item* item) {
|
InventoryComponent::OnItemEquipped += [](InventoryComponent* component, Item* item) {
|
||||||
@ -260,6 +337,11 @@ void nejlika::NejlikaHooks::InstallHooks()
|
|||||||
modifiers.insert(modifiers.end(), skillModifiers.begin(), skillModifiers.end());
|
modifiers.insert(modifiers.end(), skillModifiers.begin(), skillModifiers.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Upgrades
|
||||||
|
const auto upgradeModifiers = offenderEntity.TriggerUpgradeItems(UpgradeTriggerType::OnHit);
|
||||||
|
|
||||||
|
modifiers.insert(modifiers.end(), upgradeModifiers.begin(), upgradeModifiers.end());
|
||||||
|
|
||||||
std::unordered_set<ModifierType> damageTypes;
|
std::unordered_set<ModifierType> damageTypes;
|
||||||
|
|
||||||
for (const auto& modifier : modifiers) {
|
for (const auto& modifier : modifiers) {
|
||||||
@ -275,13 +357,14 @@ void nejlika::NejlikaHooks::InstallHooks()
|
|||||||
damageTypes.insert(modifier.GetType());
|
damageTypes.insert(modifier.GetType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the following: Offensive, Defensive, Health, Armor, Imagination
|
// Remove the following: Offensive, Defensive, Health, Armor, Imagination
|
||||||
damageTypes.erase(ModifierType::Offensive);
|
damageTypes.erase(ModifierType::Offensive);
|
||||||
damageTypes.erase(ModifierType::Defensive);
|
damageTypes.erase(ModifierType::Defensive);
|
||||||
damageTypes.erase(ModifierType::Health);
|
damageTypes.erase(ModifierType::Health);
|
||||||
damageTypes.erase(ModifierType::Armor);
|
damageTypes.erase(ModifierType::Armor);
|
||||||
damageTypes.erase(ModifierType::Imagination);
|
damageTypes.erase(ModifierType::Imagination);
|
||||||
|
damageTypes.erase(ModifierType::Damage);
|
||||||
|
damageTypes.erase(ModifierType::Invalid);
|
||||||
|
|
||||||
uint32_t totalDamage = 0;
|
uint32_t totalDamage = 0;
|
||||||
|
|
||||||
@ -291,11 +374,12 @@ void nejlika::NejlikaHooks::InstallHooks()
|
|||||||
// Calculate resistance, can't go below 20% of the original damage
|
// Calculate resistance, can't go below 20% of the original damage
|
||||||
const auto resistance = std::max(1 - (damagedEntity.CalculateResistance(type) / 100), 0.2f);
|
const auto resistance = std::max(1 - (damagedEntity.CalculateResistance(type) / 100), 0.2f);
|
||||||
|
|
||||||
damageValue *= resistance;
|
float reductedDamage = damageValue * resistance;
|
||||||
|
|
||||||
totalDamage += static_cast<uint32_t>(damageValue);
|
totalDamage += static_cast<uint32_t>(reductedDamage);
|
||||||
|
|
||||||
std::cout << "Damage type: " << magic_enum::enum_name(type) << " - " << damageValue << std::endl << " Resistance: " << resistance << std::endl;
|
std::cout << "Damage type: " << magic_enum::enum_name(type) << " - " << damageValue << std::endl;
|
||||||
|
std::cout << "Resistance: " << resistance << " - " << reductedDamage << std::endl;
|
||||||
std::cout << "Heath left: " << damaged->GetComponent<DestroyableComponent>()->GetHealth() << std::endl;
|
std::cout << "Heath left: " << damaged->GetComponent<DestroyableComponent>()->GetHealth() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,12 +409,23 @@ void nejlika::NejlikaHooks::InstallHooks()
|
|||||||
roll = std::min(roll, 5.0f);
|
roll = std::min(roll, 5.0f);
|
||||||
totalDamage += static_cast<uint32_t>(totalDamage * roll);
|
totalDamage += static_cast<uint32_t>(totalDamage * roll);
|
||||||
|
|
||||||
|
const auto effectName = std::to_string(GeneralUtils::GenerateRandomNumber<uint32_t>());
|
||||||
|
const auto damagedID = damaged->GetObjectID();
|
||||||
|
|
||||||
GameMessages::SendPlayFXEffect(
|
GameMessages::SendPlayFXEffect(
|
||||||
damaged->GetObjectID(),
|
damagedID,
|
||||||
20041,
|
1531,
|
||||||
u"onhit",
|
u"create",
|
||||||
std::to_string(GeneralUtils::GenerateRandomNumber<uint32_t>())
|
effectName
|
||||||
);
|
);
|
||||||
|
|
||||||
|
damaged->AddCallbackTimer(0.5f, [damaged, effectName] () {
|
||||||
|
GameMessages::SendStopFXEffect(
|
||||||
|
damaged,
|
||||||
|
true,
|
||||||
|
effectName
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a random +10% to the damage
|
// Add a random +10% to the damage
|
||||||
|
142
dGame/UpgradeEffect.cpp
Normal file
142
dGame/UpgradeEffect.cpp
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
#include "UpgradeEffect.h"
|
||||||
|
|
||||||
|
#include "GeneralUtils.h"
|
||||||
|
#include "GameMessages.h"
|
||||||
|
|
||||||
|
#include <magic_enum.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace nejlika;
|
||||||
|
|
||||||
|
nejlika::UpgradeEffect::UpgradeEffect(const nlohmann::json& json)
|
||||||
|
{
|
||||||
|
Load(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json nejlika::UpgradeEffect::ToJson() const
|
||||||
|
{
|
||||||
|
nlohmann::json json;
|
||||||
|
|
||||||
|
json["trigger-type"] = static_cast<int32_t>(triggerType);
|
||||||
|
|
||||||
|
nlohmann::json modifiersJson = nlohmann::json::array();
|
||||||
|
|
||||||
|
for (const auto& modifier : modifiers) {
|
||||||
|
modifiersJson.push_back(modifier.ToJson());
|
||||||
|
}
|
||||||
|
|
||||||
|
json["modifiers"] = modifiersJson;
|
||||||
|
|
||||||
|
if (!chance.empty()) {
|
||||||
|
nlohmann::json chanceJson = nlohmann::json::array();
|
||||||
|
|
||||||
|
for (const auto& scale : chance) {
|
||||||
|
chanceJson.push_back({
|
||||||
|
{"level", scale.level},
|
||||||
|
{"value", scale.value}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
json["chance"] = chanceJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (effectID != 0) {
|
||||||
|
json["effect-id"] = effectID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!effectType.empty()) {
|
||||||
|
json["effect-type"] = effectType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ModifierInstance> nejlika::UpgradeEffect::GenerateModifiers(int32_t level) const
|
||||||
|
{
|
||||||
|
std::vector<ModifierInstance> result;
|
||||||
|
|
||||||
|
for (const auto& modifier : modifiers) {
|
||||||
|
auto instances = modifier.GenerateModifiers(level);
|
||||||
|
|
||||||
|
result.insert(result.end(), instances.begin(), instances.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nejlika::UpgradeEffect::Load(const nlohmann::json& json)
|
||||||
|
{
|
||||||
|
triggerType = magic_enum::enum_cast<UpgradeTriggerType>(json["trigger-type"].get<std::string>()).value_or(UpgradeTriggerType::OnHit);
|
||||||
|
|
||||||
|
modifiers.clear();
|
||||||
|
|
||||||
|
for (const auto& modifier : json["modifiers"]) {
|
||||||
|
ModifierTemplate effect(modifier);
|
||||||
|
modifiers.push_back(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.contains("chance")) {
|
||||||
|
chance.clear();
|
||||||
|
|
||||||
|
for (const auto& scale : json["chance"]) {
|
||||||
|
chance.push_back({
|
||||||
|
scale["level"].get<int32_t>(),
|
||||||
|
scale["value"].get<float>()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.contains("effect-id")) {
|
||||||
|
effectID = json["effect-id"].get<int32_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.contains("effect-type")) {
|
||||||
|
effectType = json["effect-type"].get<std::string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float nejlika::UpgradeEffect::CalculateChance(int32_t level) const {
|
||||||
|
if (chance.empty()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the highest level that is less than or equal to the given level
|
||||||
|
float value = 0;
|
||||||
|
|
||||||
|
for (const auto& scale : chance) {
|
||||||
|
if (scale.level <= level) {
|
||||||
|
value = scale.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ModifierInstance> nejlika::UpgradeEffect::Trigger(const std::vector<UpgradeEffect>& modifiers, int32_t level, UpgradeTriggerType triggerType, LWOOBJID origin) {
|
||||||
|
std::vector<ModifierInstance> result;
|
||||||
|
|
||||||
|
for (const auto& modifier : modifiers) {
|
||||||
|
if (modifier.GetTriggerType() != triggerType) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float chanceRoll = GeneralUtils::GenerateRandomNumber<float>(0, 1);
|
||||||
|
|
||||||
|
if (chanceRoll > modifier.CalculateChance(level)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto instances = modifier.GenerateModifiers(level);
|
||||||
|
|
||||||
|
result.insert(result.end(), instances.begin(), instances.end());
|
||||||
|
|
||||||
|
GameMessages::SendPlayFXEffect(
|
||||||
|
origin,
|
||||||
|
modifier.effectID,
|
||||||
|
GeneralUtils::UTF8ToUTF16(modifier.effectType),
|
||||||
|
std::to_string(GeneralUtils::GenerateRandomNumber<size_t>())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
46
dGame/UpgradeEffect.h
Normal file
46
dGame/UpgradeEffect.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ModifierTemplate.h"
|
||||||
|
#include "UpgradeTriggerType.h"
|
||||||
|
|
||||||
|
#include <dCommonVars.h>
|
||||||
|
|
||||||
|
namespace nejlika
|
||||||
|
{
|
||||||
|
|
||||||
|
class UpgradeEffect
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UpgradeEffect(const nlohmann::json& json);
|
||||||
|
|
||||||
|
nlohmann::json ToJson() const;
|
||||||
|
|
||||||
|
std::vector<ModifierInstance> GenerateModifiers(int32_t level) const;
|
||||||
|
|
||||||
|
void Load(const nlohmann::json& json);
|
||||||
|
|
||||||
|
float CalculateChance(int32_t level) const;
|
||||||
|
|
||||||
|
static std::vector<ModifierInstance> Trigger(const std::vector<UpgradeEffect>& modifiers, int32_t level, UpgradeTriggerType triggerType, LWOOBJID origin);
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
|
||||||
|
const std::vector<ModifierTemplate>& GetModifiers() const { return modifiers; }
|
||||||
|
|
||||||
|
UpgradeTriggerType GetTriggerType() const { return triggerType; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct UpgradeScale
|
||||||
|
{
|
||||||
|
int32_t level;
|
||||||
|
float value;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<UpgradeScale> chance;
|
||||||
|
UpgradeTriggerType triggerType;
|
||||||
|
std::vector<ModifierTemplate> modifiers;
|
||||||
|
int32_t effectID = 0;
|
||||||
|
std::string effectType = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
49
dGame/UpgradeTemplate.cpp
Normal file
49
dGame/UpgradeTemplate.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include "UpgradeTemplate.h"
|
||||||
|
|
||||||
|
using namespace nejlika;
|
||||||
|
|
||||||
|
nejlika::UpgradeTemplate::UpgradeTemplate(const nlohmann::json& json)
|
||||||
|
{
|
||||||
|
Load(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json nejlika::UpgradeTemplate::ToJson() const
|
||||||
|
{
|
||||||
|
nlohmann::json json;
|
||||||
|
|
||||||
|
json["name"] = name;
|
||||||
|
json["lot"] = lot;
|
||||||
|
json["max-level"] = maxLevel;
|
||||||
|
|
||||||
|
nlohmann::json passivesJson = nlohmann::json::array();
|
||||||
|
|
||||||
|
for (const auto& passive : passives) {
|
||||||
|
passivesJson.push_back(passive.ToJson());
|
||||||
|
}
|
||||||
|
|
||||||
|
json["passives"] = passivesJson;
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nejlika::UpgradeTemplate::Load(const nlohmann::json& json)
|
||||||
|
{
|
||||||
|
name = json["name"].get<std::string>();
|
||||||
|
lot = json["lot"].get<int32_t>();
|
||||||
|
maxLevel = json["max-level"].contains("max-level") ? json["max-level"].get<int32_t>() : 1;
|
||||||
|
|
||||||
|
passives.clear();
|
||||||
|
|
||||||
|
for (const auto& passive : json["passives"]) {
|
||||||
|
UpgradeEffect effect(passive);
|
||||||
|
passives.push_back(effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ModifierInstance> nejlika::UpgradeTemplate::Trigger(int32_t level, UpgradeTriggerType triggerType, LWOOBJID origin) const {
|
||||||
|
level = std::min(level, maxLevel);
|
||||||
|
|
||||||
|
return UpgradeEffect::Trigger(passives, level, triggerType, origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
40
dGame/UpgradeTemplate.h
Normal file
40
dGame/UpgradeTemplate.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "json.hpp"
|
||||||
|
|
||||||
|
#include "UpgradeEffect.h"
|
||||||
|
|
||||||
|
namespace nejlika
|
||||||
|
{
|
||||||
|
|
||||||
|
class UpgradeTemplate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UpgradeTemplate() = default;
|
||||||
|
|
||||||
|
UpgradeTemplate(const nlohmann::json& json);
|
||||||
|
|
||||||
|
nlohmann::json ToJson() const;
|
||||||
|
|
||||||
|
void Load(const nlohmann::json& json);
|
||||||
|
|
||||||
|
const std::string& GetName() const { return name; }
|
||||||
|
int32_t GetLot() const { return lot; }
|
||||||
|
int32_t GetMaxLevel() const { return maxLevel; }
|
||||||
|
const std::vector<UpgradeEffect>& GetPassives() const { return passives; }
|
||||||
|
|
||||||
|
std::vector<ModifierInstance> Trigger(int32_t level, UpgradeTriggerType triggerType, LWOOBJID origin) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string name = "";
|
||||||
|
int32_t lot = 0;
|
||||||
|
int32_t maxLevel = 0;
|
||||||
|
std::vector<UpgradeEffect> passives;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
13
dGame/UpgradeTriggerType.h
Normal file
13
dGame/UpgradeTriggerType.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace nejlika
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class UpgradeTriggerType
|
||||||
|
{
|
||||||
|
OnHit,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -24,7 +24,13 @@ void HealBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bit_strea
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyable->Heal(this->m_health);
|
auto maxHealth = destroyable->GetMaxHealth();
|
||||||
|
|
||||||
|
// 1 health is 5% of the max health, minimum of 5 health
|
||||||
|
auto health = static_cast<int32_t>(maxHealth * 0.05f) * this->m_health;
|
||||||
|
health = std::max(5u, health);
|
||||||
|
|
||||||
|
destroyable->Heal(health);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include "CDRewardsTable.h"
|
#include "CDRewardsTable.h"
|
||||||
|
|
||||||
|
Observable<LevelProgressionComponent*> LevelProgressionComponent::OnLevelUp;
|
||||||
|
|
||||||
LevelProgressionComponent::LevelProgressionComponent(Entity* parent) : Component(parent) {
|
LevelProgressionComponent::LevelProgressionComponent(Entity* parent) : Component(parent) {
|
||||||
m_Parent = parent;
|
m_Parent = parent;
|
||||||
m_Level = 1;
|
m_Level = 1;
|
||||||
@ -80,6 +82,8 @@ void LevelProgressionComponent::HandleLevelUp() {
|
|||||||
}
|
}
|
||||||
// Tell the client we have finished sending level rewards.
|
// Tell the client we have finished sending level rewards.
|
||||||
if (rewardingItem) GameMessages::NotifyLevelRewards(m_Parent->GetObjectID(), m_Parent->GetSystemAddress(), m_Level, !rewardingItem);
|
if (rewardingItem) GameMessages::NotifyLevelRewards(m_Parent->GetObjectID(), m_Parent->GetSystemAddress(), m_Level, !rewardingItem);
|
||||||
|
|
||||||
|
OnLevelUp(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LevelProgressionComponent::SetRetroactiveBaseSpeed(){
|
void LevelProgressionComponent::SetRetroactiveBaseSpeed(){
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "Component.h"
|
#include "Component.h"
|
||||||
#include "eCharacterVersion.h"
|
#include "eCharacterVersion.h"
|
||||||
#include "eReplicaComponentType.h"
|
#include "eReplicaComponentType.h"
|
||||||
|
#include "Observable.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that handles level progression and serilization.
|
* Component that handles level progression and serilization.
|
||||||
@ -81,6 +82,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
void SetRetroactiveBaseSpeed();
|
void SetRetroactiveBaseSpeed();
|
||||||
|
|
||||||
|
static Observable<LevelProgressionComponent*> OnLevelUp;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* whether the level is dirty
|
* whether the level is dirty
|
||||||
|
@ -973,7 +973,7 @@ void GameMessages::SendResurrect(Entity* entity) {
|
|||||||
if (levelComponent) {
|
if (levelComponent) {
|
||||||
int32_t healthToRestore = levelComponent->GetLevel() >= 45 ? 8 : 4;
|
int32_t healthToRestore = levelComponent->GetLevel() >= 45 ? 8 : 4;
|
||||||
if (healthToRestore > destroyableComponent->GetMaxHealth()) healthToRestore = destroyableComponent->GetMaxHealth();
|
if (healthToRestore > destroyableComponent->GetMaxHealth()) healthToRestore = destroyableComponent->GetMaxHealth();
|
||||||
destroyableComponent->SetHealth(healthToRestore);
|
destroyableComponent->SetHealth(destroyableComponent->GetMaxHealth());
|
||||||
|
|
||||||
int32_t imaginationToRestore = levelComponent->GetLevel() >= 45 ? 20 : 6;
|
int32_t imaginationToRestore = levelComponent->GetLevel() >= 45 ? 20 : 6;
|
||||||
if (imaginationToRestore > destroyableComponent->GetMaxImagination()) imaginationToRestore = destroyableComponent->GetMaxImagination();
|
if (imaginationToRestore > destroyableComponent->GetMaxImagination()) imaginationToRestore = destroyableComponent->GetMaxImagination();
|
||||||
|
Loading…
Reference in New Issue
Block a user