diff --git a/data/actions/player.json b/data/actions/player.json index 149d05aa..15370c57 100644 --- a/data/actions/player.json +++ b/data/actions/player.json @@ -398,7 +398,18 @@ "restorePercentage": 0, "nextCombo": [], "statuses": { - "caster": [], + "caster": [ + { + "id": 83, + "duration": 20000, + "modifiers": [ + { + "modifier": "DefensePercent", + "value": 20 + } + ] + } + ], "target": [] } }, @@ -414,7 +425,18 @@ "nextCombo": [], "statuses": { "caster": [], - "target": [] + "target": [ + { + "id": 244, + "duration": 30000, + "modifiers": [ + { + "modifier": "TickDamage", + "value": 20 + } + ] + } + ] } }, "34": { @@ -478,7 +500,18 @@ 45 ], "statuses": { - "caster": [], + "caster": [ + { + "id": 85, + "duration": 24000, + "modifiers": [ + { + "modifier": "AttackPowerPercent", + "value": 20 + } + ] + } + ], "target": [] } }, @@ -493,7 +526,18 @@ "restorePercentage": 0, "nextCombo": [], "statuses": { - "caster": [], + "caster": [ + { + "id": 86, + "duration": 20000, + "modifiers": [ + { + "modifier": "AttackPowerPercent", + "value": 50 + } + ] + } + ], "target": [] } }, @@ -523,7 +567,18 @@ "restorePercentage": 0, "nextCombo": [], "statuses": { - "caster": [], + "caster": [ + { + "id": 87, + "duration": 20000, + "modifiers": [ + { + "modifier": "HPPercent", + "value": 20 + } + ] + } + ], "target": [] } }, @@ -2454,7 +2509,38 @@ "nextCombo": [], "statuses": { "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": { diff --git a/src/common/Common.h b/src/common/Common.h index 72e14d21..f1790f5b 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -887,22 +887,30 @@ namespace Sapphire::Common Perception = 73, // Unique modifiers - HPPercent = 1000, - MPPercent = 1001, - TPPercent = 1002, - GPPercent = 1003, - CPPercent = 1004, - PhysicalDamagePercent = 1005, - MagicDamagePercent = 1006, - AttackPowerPercent = 1007, - DefensePercent = 1008, - AccuracyPercent = 1009, - EvasionPercent = 1010, - MagicDefensePercent = 1011, - CriticalHitPowerPercent = 1012, - CriticalHitResiliencePercent = 1013, - CriticalHitPercent = 1014, - EnmityPercent = 1015 + TickHeal = 1000, + TickDamage = 1001, + StrengthPercent = 1002, + DexterityPercent = 1003, + VitalityPercent = 1004, + IntelligencePercent = 1005, + MindPercent = 1006, + PietyPercent = 1007, + HPPercent = 1008, + MPPercent = 1009, + TPPercent = 1010, + GPPercent = 1011, + CPPercent = 1012, + PhysicalDamagePercent = 1013, + MagicDamagePercent = 1014, + AttackPowerPercent = 1015, + DefensePercent = 1016, + AccuracyPercent = 1017, + EvasionPercent = 1018, + MagicDefensePercent = 1019, + CriticalHitPowerPercent = 1020, + CriticalHitResiliencePercent = 1021, + CriticalHitPercent = 1022, + EnmityPercent = 1023 }; enum struct ActionAspect : uint8_t diff --git a/src/tools/action_parse/main.cpp b/src/tools/action_parse/main.cpp index c542eae7..dee585cc 100644 --- a/src/tools/action_parse/main.cpp +++ b/src/tools/action_parse/main.cpp @@ -40,6 +40,7 @@ struct StatusModifier struct StatusEntry { uint16_t id; + int32_t duration; std::vector< StatusModifier > modifiers; }; @@ -76,6 +77,7 @@ void to_json( nlohmann::ordered_json& j, const StatusEntry& statusEntry ) { j = nlohmann::ordered_json{ { "id", statusEntry.id }, + { "duration", statusEntry.duration }, { "modifiers", statusEntry.modifiers } }; } diff --git a/src/world/Action/Action.cpp b/src/world/Action/Action.cpp index d78ebe2e..1b4faff6 100644 --- a/src/world/Action/Action.cpp +++ b/src/world/Action/Action.cpp @@ -431,7 +431,7 @@ void Action::Action::execute() if( !hasClientsideTarget() ) { - buildEffects(); + handleAction(); } 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 ); } -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 ); @@ -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 ); // TODO: disabled, reset kills our queued actions @@ -600,6 +611,38 @@ void Action::Action::buildEffects() // 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() { if( auto player = m_pSource->getAsPlayer() ) @@ -864,7 +907,8 @@ Entity::CharaPtr Action::Action::getHitChara() bool Action::Action::hasValidLutEntry() const { 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() diff --git a/src/world/Action/Action.h b/src/world/Action/Action.h index 04468115..f6f18304 100644 --- a/src/world/Action/Action.h +++ b/src/world/Action/Action.h @@ -105,7 +105,11 @@ namespace Sapphire::World::Action 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. diff --git a/src/world/Action/ActionLut.cpp b/src/world/Action/ActionLut.cpp index 38746ca9..69824c43 100644 --- a/src/world/Action/ActionLut.cpp +++ b/src/world/Action/ActionLut.cpp @@ -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 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 ) diff --git a/src/world/Action/ActionLut.h b/src/world/Action/ActionLut.h index 3ea20cdb..bd0fbe3f 100644 --- a/src/world/Action/ActionLut.h +++ b/src/world/Action/ActionLut.h @@ -17,6 +17,7 @@ namespace Sapphire::World::Action struct StatusEntry { uint16_t id; + int32_t duration; std::vector< StatusModifier > modifiers; }; diff --git a/src/world/Action/ActionLutData.cpp b/src/world/Action/ActionLutData.cpp index 99ee9b73..9e4c7bcd 100644 --- a/src/world/Action/ActionLutData.cpp +++ b/src/world/Action/ActionLutData.cpp @@ -85,6 +85,14 @@ std::unordered_map< std::string, Common::ParamModifier > ActionLutData::m_modifi { "Control", Common::ParamModifier::Control }, { "Gathering", Common::ParamModifier::Gathering }, { "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 }, { "MPPercent", Common::ParamModifier::MPPercent }, { "TPPercent", Common::ParamModifier::TPPercent }, diff --git a/src/world/Action/ActionLutData.h b/src/world/Action/ActionLutData.h index 61225af6..99e78f03 100644 --- a/src/world/Action/ActionLutData.h +++ b/src/world/Action/ActionLutData.h @@ -32,6 +32,7 @@ namespace Sapphire::World::Action inline void from_json( const nlohmann::json& j, StatusEntry& statusEntry ) { j.at( "id" ).get_to( statusEntry.id ); + j.at( "duration" ).get_to( statusEntry.duration ); if( j.contains( "modifiers" ) ) j.at( "modifiers" ).get_to( statusEntry.modifiers ); } diff --git a/src/world/Action/EffectBuilder.cpp b/src/world/Action/EffectBuilder.cpp index 1770e8c6..dd5bae9e 100644 --- a/src/world/Action/EffectBuilder.cpp +++ b/src/world/Action/EffectBuilder.cpp @@ -93,10 +93,10 @@ void EffectBuilder::comboSucceed( Entity::CharaPtr& target ) 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 ); - nextResult->applyStatusEffect( statusId, param ); + nextResult->applyStatusEffect( statusId, param, forSelf ); addResultToActor( target, nextResult ); } diff --git a/src/world/Action/EffectBuilder.h b/src/world/Action/EffectBuilder.h index 705690a8..c0711cf2 100644 --- a/src/world/Action/EffectBuilder.h +++ b/src/world/Action/EffectBuilder.h @@ -25,7 +25,7 @@ namespace Sapphire::World::Action 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 ); diff --git a/src/world/Action/EffectResult.cpp b/src/world/Action/EffectResult.cpp index 8ef9d68f..9de97df3 100644 --- a/src/world/Action/EffectResult.cpp +++ b/src/world/Action/EffectResult.cpp @@ -70,11 +70,13 @@ void EffectResult::comboSucceed() 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.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 ) diff --git a/src/world/Action/EffectResult.h b/src/world/Action/EffectResult.h index 38ca2b7a..48d43c71 100644 --- a/src/world/Action/EffectResult.h +++ b/src/world/Action/EffectResult.h @@ -19,7 +19,7 @@ namespace Sapphire::World::Action void restoreMP( uint32_t amount, Common::ActionEffectResultFlag flag = Common::ActionEffectResultFlag::None ); void startCombo( uint16_t actionId ); 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 ); Entity::CharaPtr getTarget() const; diff --git a/src/world/Actor/Chara.cpp b/src/world/Actor/Chara.cpp index 23f652b5..a135f1e9 100644 --- a/src/world/Actor/Chara.cpp +++ b/src/world/Actor/Chara.cpp @@ -5,7 +5,6 @@ #include #include - #include "Forwards.h" #include "Territory/Territory.h" @@ -26,6 +25,7 @@ #include "Player.h" #include "Manager/TerritoryMgr.h" #include "Manager/MgrUtil.h" +#include "Manager/PlayerMgr.h" #include "Common.h" 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 ); effect->setParam( param ); 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() @@ -644,7 +654,6 @@ void Sapphire::Entity::Chara::sendStatusEffectUpdate() { uint64_t currentTimeMs = Util::getTimeMs(); - auto statusEffectList = makeZonePacket< FFXIVIpcStatus >( getId() ); uint8_t slot = 0; for( const auto& effectIt : m_statusEffectMap ) @@ -689,7 +698,13 @@ void Sapphire::Entity::Chara::updateStatusEffects() 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 @@ -785,6 +800,47 @@ void Sapphire::Entity::Chara::setStatValue( Common::BaseParam baseParam, uint32_ 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() { uint32_t thisTickDmg = 0; @@ -795,13 +851,13 @@ void Sapphire::Entity::Chara::onTick() auto thisEffect = effectIt.second->getTickEffect(); switch( thisEffect.first ) { - case 1: + case Common::ParamModifier::TickDamage: { thisTickDmg += thisEffect.second; break; } - case 2: + case Common::ParamModifier::TickHeal: { thisTickHeal += thisEffect.second; 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 ) { takeDamage( thisTickDmg ); server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeActorControl( getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP ), thisTickDmg ) ); + if( isPlayer() ) + server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeHudParam( *getAsPlayer() ) ); + else if( isBattleNpc() ) + server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeHudParam( *getAsBNpc() ) ); } if( thisTickHeal != 0 ) @@ -823,5 +885,9 @@ void Sapphire::Entity::Chara::onTick() server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeActorControl( getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP ), thisTickHeal ) ); + if( isPlayer() ) + server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeHudParam( *getAsPlayer() ) ); + else if( isBattleNpc() ) + server().queueForPlayers( getInRangePlayerIds( isPlayer() ), makeHudParam( *getAsBNpc() ) ); } } \ No newline at end of file diff --git a/src/world/Actor/Chara.h b/src/world/Actor/Chara.h index 20449f16..a5c4de9c 100644 --- a/src/world/Actor/Chara.h +++ b/src/world/Actor/Chara.h @@ -1,6 +1,7 @@ #pragma once #include +#include "Action/ActionLut.h" #include "Forwards.h" #include "GameObject.h" @@ -8,6 +9,7 @@ #include #include #include +#include namespace Sapphire::Entity { @@ -26,10 +28,13 @@ namespace Sapphire::Entity public: 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_bonusStats{ 0 }; + ActorModifiersMap m_modifiers{ 0 }; + protected: char m_name[34]; /*! Last tick time for the actor ( in ms ) */ @@ -133,9 +138,9 @@ namespace Sapphire::Entity // add a status effect by id 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 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 void removeSingleStatusEffectFromId( uint32_t id ); @@ -159,6 +164,12 @@ namespace Sapphire::Entity 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 getHpPercent() const; diff --git a/src/world/StatusEffect/StatusEffect.cpp b/src/world/StatusEffect/StatusEffect.cpp index 1b371938..b31a0829 100644 --- a/src/world/StatusEffect/StatusEffect.cpp +++ b/src/world/StatusEffect/StatusEffect.cpp @@ -17,12 +17,20 @@ using namespace Sapphire::Common; using namespace Sapphire::Network::Packets; //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, uint32_t duration, uint32_t tickRate ) : m_id( id ), m_sourceActor( sourceActor ), m_targetActor( targetActor ), m_duration( duration ), + m_modifiers( 0 ), m_startTime( 0 ), m_tickRate( tickRate ), 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 ); } -std::pair< uint8_t, uint32_t > Sapphire::StatusEffect::StatusEffect::getTickEffect() +std::pair< ParamModifier, uint32_t > Sapphire::StatusEffect::StatusEffect::getTickEffect() { - auto thisTick = m_currTickEffect; - m_currTickEffect = std::make_pair( 0, 0 ); - return thisTick; + return m_currTickEffect; } void Sapphire::StatusEffect::StatusEffect::onTick() @@ -87,6 +93,19 @@ void Sapphire::StatusEffect::StatusEffect::applyStatus() m_startTime = Util::getTimeMs(); 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 // else you probably need to use an actorcontrol @@ -111,6 +130,15 @@ void Sapphire::StatusEffect::StatusEffect::applyStatus() void Sapphire::StatusEffect::StatusEffect::removeStatus() { 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 ); } diff --git a/src/world/StatusEffect/StatusEffect.h b/src/world/StatusEffect/StatusEffect.h index e6bb1c8e..f18ecbcf 100644 --- a/src/world/StatusEffect/StatusEffect.h +++ b/src/world/StatusEffect/StatusEffect.h @@ -2,6 +2,7 @@ #define _STATUSEFFECT_H_ #include "Forwards.h" +#include "Action/ActionLut.h" namespace Sapphire { namespace StatusEffect { @@ -10,6 +11,9 @@ namespace StatusEffect { class StatusEffect { 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, uint32_t duration, uint32_t tickRate ); @@ -41,9 +45,9 @@ public: 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; @@ -57,8 +61,8 @@ private: uint64_t m_lastTick; uint16_t m_param; 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; }; }