1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-02 16:57:47 +00:00

Merge pull request #915 from Skyliegirl33/actions

[3.x] Some initial action work (mostly statuses)
This commit is contained in:
Mordred 2023-03-08 09:21:39 +01:00 committed by GitHub
commit 801fc9da8a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 314 additions and 48 deletions

View file

@ -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": {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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