1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-28 20:27:46 +00:00

Attempt to fix combo actions.

This commit is contained in:
collett 2020-01-02 08:07:33 +09:00
parent f6bff46c9a
commit 56296d295a
8 changed files with 132 additions and 36 deletions

View file

@ -629,6 +629,7 @@ namespace Sapphire::Common
* @param value The actionid that starts/continues the combo. eg, 3617 will start a spinning slash and/or syphon strike combo * @param value The actionid that starts/continues the combo. eg, 3617 will start a spinning slash and/or syphon strike combo
*/ */
StartActionCombo = 28, StartActionCombo = 28,
ComboVisualEffect = 29,
Knockback = 33, Knockback = 33,
Mount = 38, Mount = 38,
VFX = 59, // links to VFX sheet VFX = 59, // links to VFX sheet

View file

@ -336,7 +336,7 @@ void Action::Action::execute()
} }
} }
if( isComboAction() ) if( isCorrectCombo() )
{ {
auto player = m_pSource->getAsPlayer(); auto player = m_pSource->getAsPlayer();
@ -354,7 +354,7 @@ void Action::Action::execute()
// set currently casted action as the combo action if it interrupts a combo // set currently casted action as the combo action if it interrupts a combo
// ignore it otherwise (ogcds, etc.) // ignore it otherwise (ogcds, etc.)
if( !m_actionData->preservesCombo ) if( !m_actionData->preservesCombo && ( !isComboAction() || isCorrectCombo() ) )
{ {
m_pSource->setLastComboActionId( getId() ); m_pSource->setLastComboActionId( getId() );
} }
@ -418,19 +418,40 @@ void Action::Action::buildEffects()
for( auto& actor : m_hitActors ) for( auto& actor : m_hitActors )
{ {
// todo: this is shit if( lutEntry.potency > 0 )
if( lutEntry.curePotency > 0 )
{ {
auto dmg = calcDamage( isCorrectCombo() ? lutEntry.comboPotency : lutEntry.potency );
m_effectBuilder->healTarget( actor, lutEntry.curePotency );
}
else if( lutEntry.potency > 0 )
{
auto dmg = calcDamage( lutEntry.potency );
m_effectBuilder->damageTarget( actor, dmg.first, dmg.second ); m_effectBuilder->damageTarget( actor, dmg.first, dmg.second );
if ( dmg.first > 0 ) if ( dmg.first > 0 )
actor->onActionHostile( m_pSource ); actor->onActionHostile( m_pSource );
if ( isCorrectCombo() )
{
m_effectBuilder->comboVisualEffect( actor );
}
if ( !isComboAction() || isCorrectCombo() )
{
if( lutEntry.curePotency > 0 ) // actions with self heal
{
/*
Calling m_effectBuilder->healTarget( m_pSource, lutEntry.curePotency ) seems to work fine,
but it will end up sending two Effect packets to the client. However on retail everything is in one single packet.
*/
m_effectBuilder->selfHeal( actor, m_pSource, lutEntry.curePotency );
}
if ( !m_actionData->preservesCombo ) // we need something like m_actionData->hasNextComboAction
{
m_effectBuilder->startCombo( actor, getId() );
}
}
}
else if( lutEntry.curePotency > 0 )
{
// todo: calcHealing()
m_effectBuilder->healTarget( actor, lutEntry.curePotency );
} }
} }
@ -513,7 +534,7 @@ void Action::Action::setAdditionalData( uint32_t data )
m_additionalData = data; m_additionalData = data;
} }
bool Action::Action::isComboAction() const bool Action::Action::isCorrectCombo() const
{ {
auto lastActionId = m_pSource->getLastComboActionId(); auto lastActionId = m_pSource->getLastComboActionId();
@ -525,6 +546,11 @@ bool Action::Action::isComboAction() const
return m_actionData->actionCombo == lastActionId; return m_actionData->actionCombo == lastActionId;
} }
bool Action::Action::isComboAction() const
{
return m_actionData->actionCombo != 0;
}
bool Action::Action::primaryCostCheck( bool subtractCosts ) bool Action::Action::primaryCostCheck( bool subtractCosts )
{ {
switch( m_primaryCostType ) switch( m_primaryCostType )

View file

@ -45,6 +45,8 @@ namespace Sapphire::World::Action
uint32_t getAdditionalData() const; uint32_t getAdditionalData() const;
void setAdditionalData( uint32_t data ); void setAdditionalData( uint32_t data );
bool isCorrectCombo() const;
bool isComboAction() const; bool isComboAction() const;
/*! /*!

View file

@ -31,18 +31,17 @@ uint64_t EffectBuilder::getResultDelayMs()
return Common::Util::getTimeMs() + 850; return Common::Util::getTimeMs() + 850;
} }
EffectResultPtr EffectBuilder::getResult( Entity::CharaPtr& chara ) std::shared_ptr< std::vector< EffectResultPtr > > EffectBuilder::getResultList( Entity::CharaPtr& chara )
{ {
auto it = m_resolvedEffects.find( chara->getId() ); auto it = m_resolvedEffects.find( chara->getId() );
if( it == m_resolvedEffects.end() ) if( it == m_resolvedEffects.end() )
{ {
// create a new one and return it // create a new one and return it
// todo: this feels kinda dirty but makes for easy work auto resultList = std::make_shared< std::vector< EffectResultPtr > >();
auto result = make_EffectResult( chara, getResultDelayMs() );
m_resolvedEffects[ chara->getId() ] = result; m_resolvedEffects[ chara->getId() ] = resultList;
return result; return resultList;
} }
return it->second; return it->second;
@ -50,18 +49,52 @@ EffectResultPtr EffectBuilder::getResult( Entity::CharaPtr& chara )
void EffectBuilder::healTarget( Entity::CharaPtr& target, uint32_t amount, Common::ActionHitSeverityType severity ) void EffectBuilder::healTarget( Entity::CharaPtr& target, uint32_t amount, Common::ActionHitSeverityType severity )
{ {
auto result = getResult( target ); auto resultList = getResultList( target );
assert( result ); assert( resultList );
result->heal( amount, severity ); EffectResultPtr nextResult = make_EffectResult( target, getResultDelayMs() );
nextResult->heal( amount, severity, false );
resultList->push_back( std::move( nextResult ) );
}
void EffectBuilder::selfHeal( Entity::CharaPtr& target, Entity::CharaPtr& source, uint32_t amount, Common::ActionHitSeverityType severity )
{
auto resultList = getResultList( target );
assert( resultList );
EffectResultPtr nextResult = make_EffectResult( source, getResultDelayMs() ); // heal the source actor
nextResult->heal( amount, severity, true );
resultList->push_back( std::move( nextResult ) );
} }
void EffectBuilder::damageTarget( Entity::CharaPtr& target, uint32_t amount, Common::ActionHitSeverityType severity ) void EffectBuilder::damageTarget( Entity::CharaPtr& target, uint32_t amount, Common::ActionHitSeverityType severity )
{ {
auto result = getResult( target ); auto resultList = getResultList( target );
assert( result ); assert( resultList );
result->damage( amount, severity ); EffectResultPtr nextResult = make_EffectResult( target, getResultDelayMs() );
nextResult->damage( amount, severity );
resultList->push_back( std::move( nextResult ) );
}
void EffectBuilder::startCombo( Entity::CharaPtr& target, uint16_t actionId )
{
auto resultList = getResultList( target );
assert( resultList );
EffectResultPtr nextResult = make_EffectResult( target, 0 );
nextResult->startCombo( actionId );
resultList->push_back( std::move( nextResult ) );
}
void EffectBuilder::comboVisualEffect( Entity::CharaPtr& target )
{
auto resultList = getResultList( target );
assert( resultList );
EffectResultPtr nextResult = make_EffectResult( target, 0 );
nextResult->comboVisualEffect();
resultList->push_back( std::move( nextResult ) );
} }
void EffectBuilder::buildAndSendPackets() void EffectBuilder::buildAndSendPackets()
@ -71,22 +104,29 @@ void EffectBuilder::buildAndSendPackets()
for( auto it = m_resolvedEffects.begin(); it != m_resolvedEffects.end(); ) for( auto it = m_resolvedEffects.begin(); it != m_resolvedEffects.end(); )
{ {
auto result = it->second; auto resultList = it->second;
Logger::debug( " - id: {}", result->getTarget()->getId() ); assert( resultList->size() > 0 );
auto firstResult = resultList->data()[ 0 ];
Logger::debug( " - id: {}", firstResult->getTarget()->getId() );
auto seq = m_sourceChara->getCurrentTerritory()->getNextEffectSequence(); auto seq = m_sourceChara->getCurrentTerritory()->getNextEffectSequence();
auto effectPacket = std::make_shared< Server::EffectPacket >( m_sourceChara->getId(), result->getTarget()->getId(), m_actionId ); auto effectPacket = std::make_shared< Server::EffectPacket >( m_sourceChara->getId(), firstResult->getTarget()->getId(), m_actionId );
effectPacket->setRotation( Common::Util::floatToUInt16Rot( m_sourceChara->getRot() ) ); effectPacket->setRotation( Common::Util::floatToUInt16Rot( m_sourceChara->getRot() ) );
effectPacket->setSequence( seq, m_sequence ); effectPacket->setSequence( seq, m_sequence );
effectPacket->addEffect( result->buildEffectEntry() ); for( int i = 0; i < resultList->size(); i++ )
{
auto result = resultList->data()[ i ];
effectPacket->addEffect( result->buildEffectEntry() );
// add effect to territory
m_sourceChara->getCurrentTerritory()->addEffectResult( std::move( result ) );
}
resultList->clear();
m_sourceChara->sendToInRangeSet( effectPacket, true ); m_sourceChara->sendToInRangeSet( effectPacket, true );
// add effect to territory
m_sourceChara->getCurrentTerritory()->addEffectResult( std::move( result ) );
it = m_resolvedEffects.erase( it ); it = m_resolvedEffects.erase( it );
} }
} }

View file

@ -15,14 +15,21 @@ namespace Sapphire::World::Action
void healTarget( Entity::CharaPtr& target, uint32_t amount, void healTarget( Entity::CharaPtr& target, uint32_t amount,
Common::ActionHitSeverityType severity = Common::ActionHitSeverityType::NormalHeal ); Common::ActionHitSeverityType severity = Common::ActionHitSeverityType::NormalHeal );
void selfHeal( Entity::CharaPtr& target, Entity::CharaPtr& source, uint32_t amount,
Common::ActionHitSeverityType severity = Common::ActionHitSeverityType::NormalHeal );
void damageTarget( Entity::CharaPtr& target, uint32_t amount, void damageTarget( Entity::CharaPtr& target, uint32_t amount,
Common::ActionHitSeverityType severity = Common::ActionHitSeverityType::NormalDamage ); Common::ActionHitSeverityType severity = Common::ActionHitSeverityType::NormalDamage );
void startCombo( Entity::CharaPtr& target, uint16_t actionId );
void comboVisualEffect( Entity::CharaPtr& target );
void buildAndSendPackets(); void buildAndSendPackets();
private: private:
EffectResultPtr getResult( Entity::CharaPtr& chara ); std::shared_ptr< std::vector< EffectResultPtr > > getResultList( Entity::CharaPtr& chara );
uint64_t getResultDelayMs(); uint64_t getResultDelayMs();
@ -31,7 +38,7 @@ namespace Sapphire::World::Action
uint16_t m_sequence; uint16_t m_sequence;
Entity::CharaPtr m_sourceChara; Entity::CharaPtr m_sourceChara;
std::unordered_map< uint32_t, EffectResultPtr > m_resolvedEffects; std::unordered_map< uint32_t, std::shared_ptr< std::vector< EffectResultPtr > > > m_resolvedEffects;
}; };
} }

View file

@ -14,7 +14,8 @@ EffectResult::EffectResult( Entity::CharaPtr target, uint64_t runAfter ) :
m_value( 0 ), m_value( 0 ),
m_severity( Common::ActionHitSeverityType::NormalDamage ), m_severity( Common::ActionHitSeverityType::NormalDamage ),
m_type( Common::ActionEffectType::Nothing ), m_type( Common::ActionEffectType::Nothing ),
m_param( 0 ) m_param( 0 ),
m_flag( 0 )
{ {
} }
@ -47,14 +48,28 @@ void EffectResult::damage( uint32_t amount, Common::ActionHitSeverityType severi
m_type = Common::ActionEffectType::Damage; m_type = Common::ActionEffectType::Damage;
} }
void EffectResult::heal( uint32_t amount, Sapphire::Common::ActionHitSeverityType severity ) void EffectResult::heal( uint32_t amount, Sapphire::Common::ActionHitSeverityType severity, bool isSelfHeal )
{ {
m_severity = severity; m_severity = severity;
m_value = amount; m_value = amount;
m_flag = isSelfHeal ? 0x80 : 0; // flag == 0x80 displays healing text at source actor
m_type = Common::ActionEffectType::Heal; m_type = Common::ActionEffectType::Heal;
} }
void EffectResult::startCombo( uint16_t actionId )
{
m_value = actionId;
m_flag = 0x80;
m_type = Common::ActionEffectType::StartActionCombo;
}
void EffectResult::comboVisualEffect()
{
m_type = Common::ActionEffectType::ComboVisualEffect;
}
Common::EffectEntry EffectResult::buildEffectEntry() const Common::EffectEntry EffectResult::buildEffectEntry() const
{ {
Common::EffectEntry entry{}; Common::EffectEntry entry{};
@ -64,6 +79,7 @@ Common::EffectEntry EffectResult::buildEffectEntry() const
entry.hitSeverity = m_severity; entry.hitSeverity = m_severity;
entry.effectType = m_type; entry.effectType = m_type;
entry.param = m_param; entry.param = m_param;
entry.flags = m_flag;
return entry; return entry;
} }

View file

@ -16,7 +16,9 @@ namespace Sapphire::World::Action
explicit EffectResult( Entity::CharaPtr target, uint64_t delayMs ); explicit EffectResult( Entity::CharaPtr target, uint64_t delayMs );
void damage( uint32_t amount, Common::ActionHitSeverityType severity ); void damage( uint32_t amount, Common::ActionHitSeverityType severity );
void heal( uint32_t amount, Common::ActionHitSeverityType severity ); void heal( uint32_t amount, Common::ActionHitSeverityType severity, bool isSelfHeal );
void startCombo( uint16_t actionId );
void comboVisualEffect();
Entity::CharaPtr getTarget() const; Entity::CharaPtr getTarget() const;
@ -40,6 +42,7 @@ namespace Sapphire::World::Action
uint32_t m_value; uint32_t m_value;
uint8_t m_param; uint8_t m_param;
uint8_t m_flag;
}; };
} }

View file

@ -25,13 +25,14 @@ namespace Sapphire::Network::Packets::Server
m_data.effectTargetId = targetId; m_data.effectTargetId = targetId;
m_data.effectDisplayType = Common::ActionEffectDisplayType::ShowActionName; m_data.effectDisplayType = Common::ActionEffectDisplayType::ShowActionName;
std::memset(m_data.effects, 0, sizeof(Common::EffectEntry) * 8);
} }
void addEffect( const Common::EffectEntry& effect ) void addEffect( const Common::EffectEntry& effect )
{ {
assert( m_data.effectCount <= 8 ); assert( m_data.effectCount <= 8 );
std::memset( m_data.effects, 0, sizeof( Common::EffectEntry ) * 8 );
std::memcpy( &m_data.effects[ m_data.effectCount * 8 ], &effect, sizeof( Common::EffectEntry ) ); std::memcpy( &m_data.effects[ m_data.effectCount * 8 ], &effect, sizeof( Common::EffectEntry ) );
m_data.effectCount++; m_data.effectCount++;
} }