Added upgrades

This commit is contained in:
wincent 2024-06-02 15:43:35 +02:00
parent d5b2278dc5
commit 364bcf822a
17 changed files with 531 additions and 14 deletions

View File

@ -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();

View File

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

View File

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

View File

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

View File

@ -26,6 +26,8 @@ enum class ModifierType : uint8_t
Psychic, Psychic,
Damage,
Invalid Invalid
}; };

View File

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

View File

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

View File

@ -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
View 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
View 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
View 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
View 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;
};
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <cstdint>
namespace nejlika
{
enum class UpgradeTriggerType
{
OnHit,
};
}

View File

@ -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);
} }

View File

@ -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(){

View File

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

View File

@ -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();