mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-02 00:47:45 +00:00
Merge pull request #915 from Skyliegirl33/actions
[3.x] Some initial action work (mostly statuses)
This commit is contained in:
commit
801fc9da8a
17 changed files with 314 additions and 48 deletions
|
@ -398,7 +398,18 @@
|
||||||
"restorePercentage": 0,
|
"restorePercentage": 0,
|
||||||
"nextCombo": [],
|
"nextCombo": [],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [
|
||||||
|
{
|
||||||
|
"id": 83,
|
||||||
|
"duration": 20000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "DefensePercent",
|
||||||
|
"value": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"target": []
|
"target": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -414,7 +425,18 @@
|
||||||
"nextCombo": [],
|
"nextCombo": [],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [],
|
||||||
"target": []
|
"target": [
|
||||||
|
{
|
||||||
|
"id": 244,
|
||||||
|
"duration": 30000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "TickDamage",
|
||||||
|
"value": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"34": {
|
"34": {
|
||||||
|
@ -478,7 +500,18 @@
|
||||||
45
|
45
|
||||||
],
|
],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [
|
||||||
|
{
|
||||||
|
"id": 85,
|
||||||
|
"duration": 24000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "AttackPowerPercent",
|
||||||
|
"value": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"target": []
|
"target": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -493,7 +526,18 @@
|
||||||
"restorePercentage": 0,
|
"restorePercentage": 0,
|
||||||
"nextCombo": [],
|
"nextCombo": [],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [
|
||||||
|
{
|
||||||
|
"id": 86,
|
||||||
|
"duration": 20000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "AttackPowerPercent",
|
||||||
|
"value": 50
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"target": []
|
"target": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -523,7 +567,18 @@
|
||||||
"restorePercentage": 0,
|
"restorePercentage": 0,
|
||||||
"nextCombo": [],
|
"nextCombo": [],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [
|
||||||
|
{
|
||||||
|
"id": 87,
|
||||||
|
"duration": 20000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "HPPercent",
|
||||||
|
"value": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"target": []
|
"target": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -2454,7 +2509,38 @@
|
||||||
"nextCombo": [],
|
"nextCombo": [],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [],
|
||||||
"target": []
|
"target": [
|
||||||
|
{
|
||||||
|
"id": 180,
|
||||||
|
"duration": 24000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "TickDamage",
|
||||||
|
"value": 35
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 191,
|
||||||
|
"duration": 24000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "HealingRecoveryPercent",
|
||||||
|
"value": -20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 240,
|
||||||
|
"duration": 24000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "HeavyPercent",
|
||||||
|
"value": 40
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"169": {
|
"169": {
|
||||||
|
|
|
@ -887,22 +887,30 @@ namespace Sapphire::Common
|
||||||
Perception = 73,
|
Perception = 73,
|
||||||
|
|
||||||
// Unique modifiers
|
// Unique modifiers
|
||||||
HPPercent = 1000,
|
TickHeal = 1000,
|
||||||
MPPercent = 1001,
|
TickDamage = 1001,
|
||||||
TPPercent = 1002,
|
StrengthPercent = 1002,
|
||||||
GPPercent = 1003,
|
DexterityPercent = 1003,
|
||||||
CPPercent = 1004,
|
VitalityPercent = 1004,
|
||||||
PhysicalDamagePercent = 1005,
|
IntelligencePercent = 1005,
|
||||||
MagicDamagePercent = 1006,
|
MindPercent = 1006,
|
||||||
AttackPowerPercent = 1007,
|
PietyPercent = 1007,
|
||||||
DefensePercent = 1008,
|
HPPercent = 1008,
|
||||||
AccuracyPercent = 1009,
|
MPPercent = 1009,
|
||||||
EvasionPercent = 1010,
|
TPPercent = 1010,
|
||||||
MagicDefensePercent = 1011,
|
GPPercent = 1011,
|
||||||
CriticalHitPowerPercent = 1012,
|
CPPercent = 1012,
|
||||||
CriticalHitResiliencePercent = 1013,
|
PhysicalDamagePercent = 1013,
|
||||||
CriticalHitPercent = 1014,
|
MagicDamagePercent = 1014,
|
||||||
EnmityPercent = 1015
|
AttackPowerPercent = 1015,
|
||||||
|
DefensePercent = 1016,
|
||||||
|
AccuracyPercent = 1017,
|
||||||
|
EvasionPercent = 1018,
|
||||||
|
MagicDefensePercent = 1019,
|
||||||
|
CriticalHitPowerPercent = 1020,
|
||||||
|
CriticalHitResiliencePercent = 1021,
|
||||||
|
CriticalHitPercent = 1022,
|
||||||
|
EnmityPercent = 1023
|
||||||
};
|
};
|
||||||
|
|
||||||
enum struct ActionAspect : uint8_t
|
enum struct ActionAspect : uint8_t
|
||||||
|
|
|
@ -40,6 +40,7 @@ struct StatusModifier
|
||||||
struct StatusEntry
|
struct StatusEntry
|
||||||
{
|
{
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
|
int32_t duration;
|
||||||
std::vector< StatusModifier > modifiers;
|
std::vector< StatusModifier > modifiers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -76,6 +77,7 @@ void to_json( nlohmann::ordered_json& j, const StatusEntry& statusEntry )
|
||||||
{
|
{
|
||||||
j = nlohmann::ordered_json{
|
j = nlohmann::ordered_json{
|
||||||
{ "id", statusEntry.id },
|
{ "id", statusEntry.id },
|
||||||
|
{ "duration", statusEntry.duration },
|
||||||
{ "modifiers", statusEntry.modifiers }
|
{ "modifiers", statusEntry.modifiers }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -431,7 +431,7 @@ void Action::Action::execute()
|
||||||
|
|
||||||
if( !hasClientsideTarget() )
|
if( !hasClientsideTarget() )
|
||||||
{
|
{
|
||||||
buildEffects();
|
handleAction();
|
||||||
}
|
}
|
||||||
else if( auto player = m_pSource->getAsPlayer() )
|
else if( auto player = m_pSource->getAsPlayer() )
|
||||||
{
|
{
|
||||||
|
@ -501,7 +501,15 @@ std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcHealing
|
||||||
return Math::CalcStats::calcActionHealing( *m_pSource, potency, wepDmg );
|
return Math::CalcStats::calcActionHealing( *m_pSource, potency, wepDmg );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Action::Action::buildEffects()
|
void Action::Action::applyStatusEffectSelf( uint16_t statusId, uint8_t param )
|
||||||
|
{
|
||||||
|
if( m_hitActors.size() > 0 )
|
||||||
|
getEffectbuilder()->applyStatusEffect( m_hitActors[ 0 ], statusId, param, true );
|
||||||
|
else
|
||||||
|
getEffectbuilder()->applyStatusEffect( m_pSource, statusId, param );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Action::Action::handleAction()
|
||||||
{
|
{
|
||||||
snapshotAffectedActors( m_hitActors );
|
snapshotAffectedActors( m_hitActors );
|
||||||
|
|
||||||
|
@ -593,6 +601,9 @@ void Action::Action::buildEffects()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( m_lutEntry.statuses.caster.size() > 0 || m_lutEntry.statuses.target.size() > 0 )
|
||||||
|
handleStatusEffects();
|
||||||
|
|
||||||
m_effectBuilder->buildAndSendPackets( m_hitActors );
|
m_effectBuilder->buildAndSendPackets( m_hitActors );
|
||||||
|
|
||||||
// TODO: disabled, reset kills our queued actions
|
// TODO: disabled, reset kills our queued actions
|
||||||
|
@ -600,6 +611,38 @@ void Action::Action::buildEffects()
|
||||||
// m_effectBuilder.reset();
|
// m_effectBuilder.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Action::Action::handleStatusEffects()
|
||||||
|
{
|
||||||
|
if( isComboAction() && !isCorrectCombo() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// handle caster statuses
|
||||||
|
if( m_lutEntry.statuses.caster.size() > 0 )
|
||||||
|
{
|
||||||
|
for( auto& status : m_lutEntry.statuses.caster )
|
||||||
|
{
|
||||||
|
applyStatusEffectSelf( status.id );
|
||||||
|
m_pSource->addStatusEffectByIdIfNotExist( status.id, status.duration, *m_pSource, status.modifiers );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle hit actor statuses
|
||||||
|
if( m_lutEntry.statuses.target.size() > 0 && m_hitActors.size() > 0 )
|
||||||
|
{
|
||||||
|
for( auto& actor : m_hitActors )
|
||||||
|
{
|
||||||
|
for( auto& status : m_lutEntry.statuses.target )
|
||||||
|
{
|
||||||
|
getEffectbuilder()->applyStatusEffect( actor, status.id, 0 );
|
||||||
|
actor->addStatusEffectByIdIfNotExist( status.id, status.duration, *m_pSource, status.modifiers );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( actor->getStatusEffectMap().size() > 0 )
|
||||||
|
actor->onActionHostile( m_pSource );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Action::Action::preCheck()
|
bool Action::Action::preCheck()
|
||||||
{
|
{
|
||||||
if( auto player = m_pSource->getAsPlayer() )
|
if( auto player = m_pSource->getAsPlayer() )
|
||||||
|
@ -864,7 +907,8 @@ Entity::CharaPtr Action::Action::getHitChara()
|
||||||
bool Action::Action::hasValidLutEntry() const
|
bool Action::Action::hasValidLutEntry() const
|
||||||
{
|
{
|
||||||
return m_lutEntry.potency != 0 || m_lutEntry.comboPotency != 0 || m_lutEntry.flankPotency != 0 || m_lutEntry.frontPotency != 0 ||
|
return m_lutEntry.potency != 0 || m_lutEntry.comboPotency != 0 || m_lutEntry.flankPotency != 0 || m_lutEntry.frontPotency != 0 ||
|
||||||
m_lutEntry.rearPotency != 0 || m_lutEntry.curePotency != 0 || m_lutEntry.restoreMPPercentage != 0;
|
m_lutEntry.rearPotency != 0 || m_lutEntry.curePotency != 0 || m_lutEntry.restoreMPPercentage != 0 ||
|
||||||
|
m_lutEntry.statuses.caster.size() > 0 || m_lutEntry.statuses.target.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Action::EffectBuilderPtr Action::Action::getEffectbuilder()
|
Action::EffectBuilderPtr Action::Action::getEffectbuilder()
|
||||||
|
|
|
@ -105,7 +105,11 @@ namespace Sapphire::World::Action
|
||||||
|
|
||||||
EffectBuilderPtr getEffectbuilder();
|
EffectBuilderPtr getEffectbuilder();
|
||||||
|
|
||||||
void buildEffects();
|
void applyStatusEffectSelf( uint16_t statusId, uint8_t param = 0 );
|
||||||
|
|
||||||
|
void handleAction();
|
||||||
|
|
||||||
|
void handleStatusEffects();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Adds an actor filter to this action.
|
* @brief Adds an actor filter to this action.
|
||||||
|
|
|
@ -15,7 +15,8 @@ bool ActionLut::validEntryExists( uint16_t actionId )
|
||||||
|
|
||||||
// if all of the fields are 0, it's not 'valid' due to parse error or no useful data in the tooltip
|
// if all of the fields are 0, it's not 'valid' due to parse error or no useful data in the tooltip
|
||||||
return entry.potency != 0 || entry.comboPotency != 0 || entry.flankPotency != 0 || entry.frontPotency != 0 ||
|
return entry.potency != 0 || entry.comboPotency != 0 || entry.flankPotency != 0 || entry.frontPotency != 0 ||
|
||||||
entry.rearPotency != 0 || entry.curePotency != 0;
|
entry.rearPotency != 0 || entry.curePotency != 0 ||
|
||||||
|
entry.statuses.caster.size() > 0 || entry.statuses.target.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ActionEntry& ActionLut::getEntry( uint16_t actionId )
|
const ActionEntry& ActionLut::getEntry( uint16_t actionId )
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace Sapphire::World::Action
|
||||||
struct StatusEntry
|
struct StatusEntry
|
||||||
{
|
{
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
|
int32_t duration;
|
||||||
std::vector< StatusModifier > modifiers;
|
std::vector< StatusModifier > modifiers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,14 @@ std::unordered_map< std::string, Common::ParamModifier > ActionLutData::m_modifi
|
||||||
{ "Control", Common::ParamModifier::Control },
|
{ "Control", Common::ParamModifier::Control },
|
||||||
{ "Gathering", Common::ParamModifier::Gathering },
|
{ "Gathering", Common::ParamModifier::Gathering },
|
||||||
{ "Perception", Common::ParamModifier::Perception },
|
{ "Perception", Common::ParamModifier::Perception },
|
||||||
|
{ "TickHeal", Common::ParamModifier::TickHeal },
|
||||||
|
{ "TickDamage", Common::ParamModifier::TickDamage },
|
||||||
|
{ "StrengthPercent", Common::ParamModifier::StrengthPercent },
|
||||||
|
{ "DexterityPercent", Common::ParamModifier::DexterityPercent },
|
||||||
|
{ "VitalityPercent", Common::ParamModifier::VitalityPercent },
|
||||||
|
{ "IntelligencePercent", Common::ParamModifier::IntelligencePercent },
|
||||||
|
{ "MindPercent", Common::ParamModifier::MindPercent },
|
||||||
|
{ "PietyPercent", Common::ParamModifier::PietyPercent },
|
||||||
{ "HPPercent", Common::ParamModifier::HPPercent },
|
{ "HPPercent", Common::ParamModifier::HPPercent },
|
||||||
{ "MPPercent", Common::ParamModifier::MPPercent },
|
{ "MPPercent", Common::ParamModifier::MPPercent },
|
||||||
{ "TPPercent", Common::ParamModifier::TPPercent },
|
{ "TPPercent", Common::ParamModifier::TPPercent },
|
||||||
|
|
|
@ -32,6 +32,7 @@ namespace Sapphire::World::Action
|
||||||
inline void from_json( const nlohmann::json& j, StatusEntry& statusEntry )
|
inline void from_json( const nlohmann::json& j, StatusEntry& statusEntry )
|
||||||
{
|
{
|
||||||
j.at( "id" ).get_to( statusEntry.id );
|
j.at( "id" ).get_to( statusEntry.id );
|
||||||
|
j.at( "duration" ).get_to( statusEntry.duration );
|
||||||
if( j.contains( "modifiers" ) )
|
if( j.contains( "modifiers" ) )
|
||||||
j.at( "modifiers" ).get_to( statusEntry.modifiers );
|
j.at( "modifiers" ).get_to( statusEntry.modifiers );
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,10 +93,10 @@ void EffectBuilder::comboSucceed( Entity::CharaPtr& target )
|
||||||
addResultToActor( target, nextResult );
|
addResultToActor( target, nextResult );
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectBuilder::applyStatusEffect( Entity::CharaPtr& target, uint16_t statusId, uint8_t param )
|
void EffectBuilder::applyStatusEffect( Entity::CharaPtr& target, uint16_t statusId, uint8_t param, bool forSelf )
|
||||||
{
|
{
|
||||||
EffectResultPtr nextResult = make_EffectResult( target, 0 );
|
EffectResultPtr nextResult = make_EffectResult( target, 0 );
|
||||||
nextResult->applyStatusEffect( statusId, param );
|
nextResult->applyStatusEffect( statusId, param, forSelf );
|
||||||
addResultToActor( target, nextResult );
|
addResultToActor( target, nextResult );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace Sapphire::World::Action
|
||||||
|
|
||||||
void comboSucceed( Entity::CharaPtr& target );
|
void comboSucceed( Entity::CharaPtr& target );
|
||||||
|
|
||||||
void applyStatusEffect( Entity::CharaPtr& target, uint16_t statusId, uint8_t param );
|
void applyStatusEffect( Entity::CharaPtr& target, uint16_t statusId, uint8_t param, bool forSelf = false );
|
||||||
|
|
||||||
void mount( Entity::CharaPtr& target, uint16_t mountId );
|
void mount( Entity::CharaPtr& target, uint16_t mountId );
|
||||||
|
|
||||||
|
|
|
@ -70,11 +70,13 @@ void EffectResult::comboSucceed()
|
||||||
m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_COMBO_HIT;
|
m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_COMBO_HIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectResult::applyStatusEffect( uint16_t statusId, uint8_t param )
|
void EffectResult::applyStatusEffect( uint16_t statusId, uint8_t param, bool forSelf )
|
||||||
{
|
{
|
||||||
m_result.Value = static_cast< int16_t >( statusId );
|
m_result.Value = static_cast< int16_t >( statusId );
|
||||||
m_result.Arg2 = param;
|
m_result.Arg2 = param;
|
||||||
m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS;
|
if( forSelf )
|
||||||
|
m_result.Flag = static_cast< uint8_t >( Common::ActionEffectResultFlag::EffectOnSource );
|
||||||
|
m_result.Type = forSelf ? Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS_ME : Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectResult::mount( uint16_t mountId )
|
void EffectResult::mount( uint16_t mountId )
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace Sapphire::World::Action
|
||||||
void restoreMP( uint32_t amount, Common::ActionEffectResultFlag flag = Common::ActionEffectResultFlag::None );
|
void restoreMP( uint32_t amount, Common::ActionEffectResultFlag flag = Common::ActionEffectResultFlag::None );
|
||||||
void startCombo( uint16_t actionId );
|
void startCombo( uint16_t actionId );
|
||||||
void comboSucceed();
|
void comboSucceed();
|
||||||
void applyStatusEffect( uint16_t statusId, uint8_t param );
|
void applyStatusEffect( uint16_t statusId, uint8_t param, bool forSelf );
|
||||||
void mount( uint16_t mountId );
|
void mount( uint16_t mountId );
|
||||||
|
|
||||||
Entity::CharaPtr getTarget() const;
|
Entity::CharaPtr getTarget() const;
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include <Network/CommonActorControl.h>
|
#include <Network/CommonActorControl.h>
|
||||||
#include <Service.h>
|
#include <Service.h>
|
||||||
|
|
||||||
|
|
||||||
#include "Forwards.h"
|
#include "Forwards.h"
|
||||||
|
|
||||||
#include "Territory/Territory.h"
|
#include "Territory/Territory.h"
|
||||||
|
@ -26,6 +25,7 @@
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "Manager/TerritoryMgr.h"
|
#include "Manager/TerritoryMgr.h"
|
||||||
#include "Manager/MgrUtil.h"
|
#include "Manager/MgrUtil.h"
|
||||||
|
#include "Manager/PlayerMgr.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
using namespace Sapphire::Common;
|
using namespace Sapphire::Common;
|
||||||
|
@ -559,7 +559,17 @@ void Sapphire::Entity::Chara::addStatusEffectByIdIfNotExist( uint32_t id, int32_
|
||||||
auto effect = StatusEffect::make_StatusEffect( id, source.getAsChara(), getAsChara(), duration, 3000 );
|
auto effect = StatusEffect::make_StatusEffect( id, source.getAsChara(), getAsChara(), duration, 3000 );
|
||||||
effect->setParam( param );
|
effect->setParam( param );
|
||||||
addStatusEffect( effect );
|
addStatusEffect( effect );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::Chara::addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Chara& source,
|
||||||
|
std::vector< World::Action::StatusModifier >& modifiers, uint16_t param )
|
||||||
|
{
|
||||||
|
if( hasStatusEffect( id ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto effect = StatusEffect::make_StatusEffect( id, source.getAsChara(), getAsChara(), duration, modifiers, 3000 );
|
||||||
|
effect->setParam( param );
|
||||||
|
addStatusEffect( effect );
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t Sapphire::Entity::Chara::getStatusEffectFreeSlot()
|
int8_t Sapphire::Entity::Chara::getStatusEffectFreeSlot()
|
||||||
|
@ -644,7 +654,6 @@ void Sapphire::Entity::Chara::sendStatusEffectUpdate()
|
||||||
{
|
{
|
||||||
uint64_t currentTimeMs = Util::getTimeMs();
|
uint64_t currentTimeMs = Util::getTimeMs();
|
||||||
|
|
||||||
|
|
||||||
auto statusEffectList = makeZonePacket< FFXIVIpcStatus >( getId() );
|
auto statusEffectList = makeZonePacket< FFXIVIpcStatus >( getId() );
|
||||||
uint8_t slot = 0;
|
uint8_t slot = 0;
|
||||||
for( const auto& effectIt : m_statusEffectMap )
|
for( const auto& effectIt : m_statusEffectMap )
|
||||||
|
@ -689,7 +698,13 @@ void Sapphire::Entity::Chara::updateStatusEffects()
|
||||||
|
|
||||||
bool Sapphire::Entity::Chara::hasStatusEffect( uint32_t id )
|
bool Sapphire::Entity::Chara::hasStatusEffect( uint32_t id )
|
||||||
{
|
{
|
||||||
return m_statusEffectMap.find( id ) != m_statusEffectMap.end();
|
for( const auto& [ key, val ] : m_statusEffectMap )
|
||||||
|
{
|
||||||
|
if( val->getId() == id )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t Sapphire::Entity::Chara::getLastUpdateTime() const
|
int64_t Sapphire::Entity::Chara::getLastUpdateTime() const
|
||||||
|
@ -785,6 +800,47 @@ void Sapphire::Entity::Chara::setStatValue( Common::BaseParam baseParam, uint32_
|
||||||
m_baseStats[ index ] = value;
|
m_baseStats[ index ] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Sapphire::Entity::Chara::getModifier( Common::ParamModifier paramModifier ) const
|
||||||
|
{
|
||||||
|
if( m_modifiers.find( paramModifier ) == m_modifiers.end() )
|
||||||
|
return paramModifier >= Common::ParamModifier::StrengthPercent ? 1.0f : 0;
|
||||||
|
|
||||||
|
auto& mod = m_modifiers.at( paramModifier );
|
||||||
|
if( paramModifier >= Common::ParamModifier::StrengthPercent )
|
||||||
|
{
|
||||||
|
auto valPercent = 1.0f;
|
||||||
|
for( const auto val : mod )
|
||||||
|
valPercent *= 1.0f + ( val / 100.0f );
|
||||||
|
return valPercent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::accumulate( mod.begin(), mod.end(), 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::Chara::addModifier( Common::ParamModifier paramModifier, int32_t value )
|
||||||
|
{
|
||||||
|
m_modifiers[ paramModifier ].push_back( value );
|
||||||
|
|
||||||
|
if( auto pPlayer = this->getAsPlayer(); pPlayer )
|
||||||
|
Common::Service< World::Manager::PlayerMgr >::ref().sendDebug( *pPlayer, "Modifier: {}, value: {}", static_cast< int32_t >( paramModifier ), getModifier( paramModifier ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::Chara::delModifier( Common::ParamModifier paramModifier, int32_t value )
|
||||||
|
{
|
||||||
|
assert( m_modifiers.count( paramModifier ) != 0 );
|
||||||
|
auto& mod = m_modifiers.at( paramModifier );
|
||||||
|
|
||||||
|
mod.erase( std::remove( mod.begin(), mod.end(), value ), mod.end() );
|
||||||
|
|
||||||
|
if( mod.size() == 0 )
|
||||||
|
m_modifiers.erase( paramModifier );
|
||||||
|
|
||||||
|
if( auto pPlayer = this->getAsPlayer(); pPlayer )
|
||||||
|
Common::Service< World::Manager::PlayerMgr >::ref().sendDebug( *pPlayer, "Modifier: {}, value: {}", static_cast< int32_t >( paramModifier ), getModifier( paramModifier ) );
|
||||||
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::Chara::onTick()
|
void Sapphire::Entity::Chara::onTick()
|
||||||
{
|
{
|
||||||
uint32_t thisTickDmg = 0;
|
uint32_t thisTickDmg = 0;
|
||||||
|
@ -795,13 +851,13 @@ void Sapphire::Entity::Chara::onTick()
|
||||||
auto thisEffect = effectIt.second->getTickEffect();
|
auto thisEffect = effectIt.second->getTickEffect();
|
||||||
switch( thisEffect.first )
|
switch( thisEffect.first )
|
||||||
{
|
{
|
||||||
case 1:
|
case Common::ParamModifier::TickDamage:
|
||||||
{
|
{
|
||||||
thisTickDmg += thisEffect.second;
|
thisTickDmg += thisEffect.second;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 2:
|
case Common::ParamModifier::TickHeal:
|
||||||
{
|
{
|
||||||
thisTickHeal += thisEffect.second;
|
thisTickHeal += thisEffect.second;
|
||||||
break;
|
break;
|
||||||
|
@ -809,12 +865,18 @@ void Sapphire::Entity::Chara::onTick()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: don't really like how this is handled
|
||||||
|
// TODO: calculate actual damage from potency
|
||||||
if( thisTickDmg != 0 )
|
if( thisTickDmg != 0 )
|
||||||
{
|
{
|
||||||
takeDamage( thisTickDmg );
|
takeDamage( thisTickDmg );
|
||||||
server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeActorControl( getId(), HPFloatingText, 0,
|
server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeActorControl( getId(), HPFloatingText, 0,
|
||||||
static_cast< uint8_t >( ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP ),
|
static_cast< uint8_t >( ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP ),
|
||||||
thisTickDmg ) );
|
thisTickDmg ) );
|
||||||
|
if( isPlayer() )
|
||||||
|
server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeHudParam( *getAsPlayer() ) );
|
||||||
|
else if( isBattleNpc() )
|
||||||
|
server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeHudParam( *getAsBNpc() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( thisTickHeal != 0 )
|
if( thisTickHeal != 0 )
|
||||||
|
@ -823,5 +885,9 @@ void Sapphire::Entity::Chara::onTick()
|
||||||
server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeActorControl( getId(), HPFloatingText, 0,
|
server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeActorControl( getId(), HPFloatingText, 0,
|
||||||
static_cast< uint8_t >( ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP ),
|
static_cast< uint8_t >( ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP ),
|
||||||
thisTickHeal ) );
|
thisTickHeal ) );
|
||||||
|
if( isPlayer() )
|
||||||
|
server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeHudParam( *getAsPlayer() ) );
|
||||||
|
else if( isBattleNpc() )
|
||||||
|
server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeHudParam( *getAsBNpc() ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Common.h>
|
#include <Common.h>
|
||||||
|
#include "Action/ActionLut.h"
|
||||||
|
|
||||||
#include "Forwards.h"
|
#include "Forwards.h"
|
||||||
#include "GameObject.h"
|
#include "GameObject.h"
|
||||||
|
@ -8,6 +9,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
namespace Sapphire::Entity
|
namespace Sapphire::Entity
|
||||||
{
|
{
|
||||||
|
@ -26,10 +28,13 @@ namespace Sapphire::Entity
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using ActorStatsArray = std::array< uint32_t, STAT_ARRAY_SIZE >;
|
using ActorStatsArray = std::array< uint32_t, STAT_ARRAY_SIZE >;
|
||||||
|
using ActorModifiersMap = std::unordered_map< Common::ParamModifier, std::vector< int32_t > >;
|
||||||
|
|
||||||
ActorStatsArray m_baseStats{ 0 };
|
ActorStatsArray m_baseStats{ 0 };
|
||||||
ActorStatsArray m_bonusStats{ 0 };
|
ActorStatsArray m_bonusStats{ 0 };
|
||||||
|
|
||||||
|
ActorModifiersMap m_modifiers{ 0 };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
char m_name[34];
|
char m_name[34];
|
||||||
/*! Last tick time for the actor ( in ms ) */
|
/*! Last tick time for the actor ( in ms ) */
|
||||||
|
@ -133,9 +138,9 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
// add a status effect by id
|
// add a status effect by id
|
||||||
void addStatusEffectById( uint32_t id, int32_t duration, Entity::Chara& source, uint16_t param = 0 );
|
void addStatusEffectById( uint32_t id, int32_t duration, Entity::Chara& source, uint16_t param = 0 );
|
||||||
|
|
||||||
// add a status effect by id if it doesn't exist
|
// add a status effect by id if it doesn't exist
|
||||||
void addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Chara& source, uint16_t param = 0 );
|
void addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Chara& source, uint16_t param = 0 );
|
||||||
|
void addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Chara& source, std::vector< World::Action::StatusModifier >& modifiers, uint16_t param = 0 );
|
||||||
|
|
||||||
// remove a status effect by id
|
// remove a status effect by id
|
||||||
void removeSingleStatusEffectFromId( uint32_t id );
|
void removeSingleStatusEffectFromId( uint32_t id );
|
||||||
|
@ -159,6 +164,12 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
void setStatValue( Common::BaseParam baseParam, uint32_t value );
|
void setStatValue( Common::BaseParam baseParam, uint32_t value );
|
||||||
|
|
||||||
|
float getModifier( Common::ParamModifier paramModifier ) const;
|
||||||
|
|
||||||
|
void addModifier( Common::ParamModifier paramModifier, int32_t value );
|
||||||
|
|
||||||
|
void delModifier( Common::ParamModifier paramModifier, int32_t value );
|
||||||
|
|
||||||
uint32_t getHp() const;
|
uint32_t getHp() const;
|
||||||
|
|
||||||
uint32_t getHpPercent() const;
|
uint32_t getHpPercent() const;
|
||||||
|
|
|
@ -17,12 +17,20 @@ using namespace Sapphire::Common;
|
||||||
using namespace Sapphire::Network::Packets;
|
using namespace Sapphire::Network::Packets;
|
||||||
//using namespace Sapphire::Network::Packets::WorldPackets::Server;
|
//using namespace Sapphire::Network::Packets::WorldPackets::Server;
|
||||||
|
|
||||||
|
Sapphire::StatusEffect::StatusEffect::StatusEffect( uint32_t id, Entity::CharaPtr sourceActor, Entity::CharaPtr targetActor,
|
||||||
|
uint32_t duration, std::vector< World::Action::StatusModifier >& modifiers, uint32_t tickRate ) :
|
||||||
|
StatusEffect( id, sourceActor, targetActor, duration, tickRate )
|
||||||
|
{
|
||||||
|
m_modifiers = std::move( modifiers );
|
||||||
|
}
|
||||||
|
|
||||||
Sapphire::StatusEffect::StatusEffect::StatusEffect( uint32_t id, Entity::CharaPtr sourceActor, Entity::CharaPtr targetActor,
|
Sapphire::StatusEffect::StatusEffect::StatusEffect( uint32_t id, Entity::CharaPtr sourceActor, Entity::CharaPtr targetActor,
|
||||||
uint32_t duration, uint32_t tickRate ) :
|
uint32_t duration, uint32_t tickRate ) :
|
||||||
m_id( id ),
|
m_id( id ),
|
||||||
m_sourceActor( sourceActor ),
|
m_sourceActor( sourceActor ),
|
||||||
m_targetActor( targetActor ),
|
m_targetActor( targetActor ),
|
||||||
m_duration( duration ),
|
m_duration( duration ),
|
||||||
|
m_modifiers( 0 ),
|
||||||
m_startTime( 0 ),
|
m_startTime( 0 ),
|
||||||
m_tickRate( tickRate ),
|
m_tickRate( tickRate ),
|
||||||
m_lastTick( 0 )
|
m_lastTick( 0 )
|
||||||
|
@ -47,16 +55,14 @@ Sapphire::StatusEffect::StatusEffect::~StatusEffect()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::StatusEffect::StatusEffect::registerTickEffect( uint8_t type, uint32_t param )
|
void Sapphire::StatusEffect::StatusEffect::registerTickEffect( ParamModifier type, uint32_t param )
|
||||||
{
|
{
|
||||||
m_currTickEffect = std::make_pair( type, param );
|
m_currTickEffect = std::make_pair( type, param );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair< uint8_t, uint32_t > Sapphire::StatusEffect::StatusEffect::getTickEffect()
|
std::pair< ParamModifier, uint32_t > Sapphire::StatusEffect::StatusEffect::getTickEffect()
|
||||||
{
|
{
|
||||||
auto thisTick = m_currTickEffect;
|
return m_currTickEffect;
|
||||||
m_currTickEffect = std::make_pair( 0, 0 );
|
|
||||||
return thisTick;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::StatusEffect::StatusEffect::onTick()
|
void Sapphire::StatusEffect::StatusEffect::onTick()
|
||||||
|
@ -87,6 +93,19 @@ void Sapphire::StatusEffect::StatusEffect::applyStatus()
|
||||||
m_startTime = Util::getTimeMs();
|
m_startTime = Util::getTimeMs();
|
||||||
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
||||||
|
|
||||||
|
for( const auto& mod : m_modifiers )
|
||||||
|
{
|
||||||
|
// TODO: ticks
|
||||||
|
if( mod.modifier != Common::ParamModifier::TickDamage && mod.modifier != Common::ParamModifier::TickHeal )
|
||||||
|
m_targetActor->addModifier( mod.modifier, mod.value );
|
||||||
|
else if( mod.modifier == Common::ParamModifier::TickDamage )
|
||||||
|
registerTickEffect( mod.modifier, mod.value );
|
||||||
|
else if( mod.modifier == Common::ParamModifier::TickHeal )
|
||||||
|
registerTickEffect( mod.modifier, mod.value );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_targetActor->calculateStats();
|
||||||
|
|
||||||
// this is only right when an action is being used by the player
|
// this is only right when an action is being used by the player
|
||||||
// else you probably need to use an actorcontrol
|
// else you probably need to use an actorcontrol
|
||||||
|
|
||||||
|
@ -111,6 +130,15 @@ void Sapphire::StatusEffect::StatusEffect::applyStatus()
|
||||||
void Sapphire::StatusEffect::StatusEffect::removeStatus()
|
void Sapphire::StatusEffect::StatusEffect::removeStatus()
|
||||||
{
|
{
|
||||||
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
||||||
|
|
||||||
|
for( const auto& mod : m_modifiers )
|
||||||
|
{
|
||||||
|
if( mod.modifier != Common::ParamModifier::TickDamage && mod.modifier != Common::ParamModifier::TickHeal )
|
||||||
|
m_targetActor->delModifier( mod.modifier, mod.value );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_targetActor->calculateStats();
|
||||||
|
|
||||||
scriptMgr.onStatusTimeOut( m_targetActor, m_id );
|
scriptMgr.onStatusTimeOut( m_targetActor, m_id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define _STATUSEFFECT_H_
|
#define _STATUSEFFECT_H_
|
||||||
|
|
||||||
#include "Forwards.h"
|
#include "Forwards.h"
|
||||||
|
#include "Action/ActionLut.h"
|
||||||
|
|
||||||
namespace Sapphire {
|
namespace Sapphire {
|
||||||
namespace StatusEffect {
|
namespace StatusEffect {
|
||||||
|
@ -10,6 +11,9 @@ namespace StatusEffect {
|
||||||
class StatusEffect
|
class StatusEffect
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
StatusEffect( uint32_t id, Entity::CharaPtr sourceActor, Entity::CharaPtr targetActor,
|
||||||
|
uint32_t duration, std::vector< World::Action::StatusModifier >& modifiers, uint32_t tickRate );
|
||||||
|
|
||||||
StatusEffect( uint32_t id, Entity::CharaPtr sourceActor, Entity::CharaPtr targetActor,
|
StatusEffect( uint32_t id, Entity::CharaPtr sourceActor, Entity::CharaPtr targetActor,
|
||||||
uint32_t duration, uint32_t tickRate );
|
uint32_t duration, uint32_t tickRate );
|
||||||
|
|
||||||
|
@ -41,9 +45,9 @@ public:
|
||||||
|
|
||||||
void setParam( uint16_t param );
|
void setParam( uint16_t param );
|
||||||
|
|
||||||
void registerTickEffect( uint8_t type, uint32_t param );
|
void registerTickEffect( Common::ParamModifier type, uint32_t param );
|
||||||
|
|
||||||
std::pair< uint8_t, uint32_t > getTickEffect();
|
std::pair< Common::ParamModifier, uint32_t > getTickEffect();
|
||||||
|
|
||||||
const std::string& getName() const;
|
const std::string& getName() const;
|
||||||
|
|
||||||
|
@ -57,8 +61,8 @@ private:
|
||||||
uint64_t m_lastTick;
|
uint64_t m_lastTick;
|
||||||
uint16_t m_param;
|
uint16_t m_param;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
std::pair< uint8_t, uint32_t > m_currTickEffect;
|
std::pair< Common::ParamModifier, uint32_t > m_currTickEffect;
|
||||||
|
std::vector< World::Action::StatusModifier > m_modifiers;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue