1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-26 03:27:44 +00:00

Implement mount action and unlock mount list

This commit is contained in:
collett 2020-01-23 22:27:05 +09:00
parent faa763fdf7
commit 8d10a34174
16 changed files with 155 additions and 9 deletions

View file

@ -633,10 +633,10 @@ namespace Sapphire::Common
* @param flags Required to be 128, doesn't show combo rings on hotbars otherwise
* @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, // actually this is more likely "ActionComplete" or something like that
ComboSucceed = 29,
Knockback = 33,
Mount = 38,
Mount = 39,
VFX = 59, // links to VFX sheet
};
@ -1010,6 +1010,7 @@ namespace Sapphire::Common
{
SingleTarget = 1,
CircularAOE = 2,
Type3 = 3, // another single target? no idea how to call it
RectangularAOE = 4,
CircularAoEPlaced = 7
};

View file

@ -207,7 +207,7 @@ namespace Sapphire::Network::Packets
QuestTracker = 0x0289, // updated 5.18
Mount = 0x02F0, // updated 5.18
Mount = 0x038F, // updated 5.18
DirectorVars = 0x00E6, // updated 5.18
SomeDirectorUnk1 = 0x0084, // updated 5.18

View file

@ -835,10 +835,11 @@ namespace Sapphire::Network::Packets::Server
uint16_t action_id;
Common::SkillType skillType;
uint8_t unknown;
uint32_t unknown_1; // Also action id
uint32_t unknown_1; // action id or mount id
float cast_time;
uint32_t target_id;
float rotation; // In radians
uint16_t rotation;
uint16_t flag; // 1 = interruptible blinking cast bar
uint32_t unknown_2;
uint16_t posX;
uint16_t posY;

View file

@ -287,7 +287,7 @@ void Action::Action::start()
data.posX = Common::Util::floatToUInt16( pos.x );
data.posY = Common::Util::floatToUInt16( pos.y );
data.posZ = Common::Util::floatToUInt16( pos.z );
data.rotation = m_pSource->getRot();
data.rotation = Common::Util::floatToUInt16Rot( m_pSource->getRot() );
m_pSource->sendToInRangeSet( castPacket, true );
@ -763,6 +763,7 @@ void Action::Action::addDefaultActorFilters()
switch( m_castType )
{
case Common::CastType::SingleTarget:
case Common::CastType::Type3:
{
auto filter = std::make_shared< World::Util::ActorFilterSingleTarget >( static_cast< uint32_t >( m_targetId ) );

View file

@ -87,7 +87,7 @@ namespace Sapphire::World::Action
* @brief Tests if an action is castable by the current source chara
* @return true if castable, false if the caster doesn't meet the requirements
*/
bool preCheck();
virtual bool preCheck();
/*!
* @brief Snapshots characters affected by a cast.

View file

@ -99,6 +99,13 @@ void EffectBuilder::statusNoEffect( Entity::CharaPtr& target, uint16_t statusId
moveToResultList( target, nextResult );
}
void EffectBuilder::mount( Entity::CharaPtr& target, uint16_t mountId, uint64_t resultDelayMs )
{
EffectResultPtr nextResult = make_EffectResult( target, Common::Util::getTimeMs() + resultDelayMs );
nextResult->mount( mountId );
moveToResultList( target, nextResult );
}
void EffectBuilder::setAnimationLock( float animationLock )
{
m_animationLock = animationLock;

View file

@ -33,6 +33,8 @@ namespace Sapphire::World::Action
void statusNoEffect( Entity::CharaPtr& target, uint16_t statusId );
void mount( Entity::CharaPtr& target, uint16_t mountId, uint64_t resultDelayMs = 600 );
void buildAndSendPackets();
private:

View file

@ -3,6 +3,7 @@
#include <Util/Util.h>
#include "Actor/Chara.h"
#include "Actor/Player.h"
using namespace Sapphire;
using namespace Sapphire::World::Action;
@ -114,6 +115,14 @@ void EffectResult::statusNoEffect( uint16_t statusId )
m_type = Common::ActionEffectType::StatusNoEffect;
}
void EffectResult::mount( uint16_t moundId )
{
m_value = moundId;
m_param0 = 1;
m_type = Common::ActionEffectType::Mount;
}
Common::EffectEntry EffectResult::buildEffectEntry() const
{
Common::EffectEntry entry{};
@ -184,6 +193,13 @@ void EffectResult::execute()
break;
}
case Common::ActionEffectType::Mount:
{
auto pPlayer = m_target->getAsPlayer();
pPlayer->mount( m_value );
break;
}
default:
break;
}

View file

@ -26,6 +26,7 @@ namespace Sapphire::World::Action
void applyStatusEffect( uint16_t statusId, uint32_t duration, uint16_t param );
void applyStatusEffect( StatusEffect::StatusEffectPtr pStatusEffect );
void statusNoEffect( uint16_t statusId );
void mount( uint16_t moundId );
Entity::CharaPtr getSource() const;
Entity::CharaPtr getTarget() const;

View file

@ -0,0 +1,68 @@
#include "MountAction.h"
#include <Exd/ExdDataGenerated.h>
#include "Actor/Player.h"
#include <Network/CommonActorControl.h>
#include "Network/PacketWrappers/ActorControlSelfPacket.h"
#include <Util/UtilMath.h>
using namespace Sapphire;
using namespace Sapphire::Network::Packets;
using namespace Sapphire::Network::Packets::Server;
using namespace Sapphire::Network::ActorControl;
using namespace Sapphire::World::Action;
MountAction::MountAction( Sapphire::Entity::CharaPtr source, uint32_t mountId, uint16_t sequence, Data::ActionPtr actionData, Sapphire::FrameworkPtr fw ) :
Action::Action( source, 4, sequence, actionData, fw ),
m_mountId( mountId )
{
}
bool MountAction::preCheck()
{
// todo: check if mount is unlocked
return m_pSource->isPlayer();
}
void MountAction::start()
{
assert( m_pSource );
m_startTime = Common::Util::getTimeMs();
auto player = m_pSource->getAsPlayer();
auto castPacket = makeZonePacket< Server::FFXIVIpcActorCast >( getId() );
auto& data = castPacket->data();
data.action_id = static_cast< uint16_t >( m_id );
data.skillType = Common::SkillType::MountSkill;
data.unknown_1 = m_mountId;
data.cast_time = m_castTimeMs / 1000.f;
data.target_id = static_cast< uint32_t >( m_targetId );
data.unknown_2 = 0xE0000000;
auto pos = m_pSource->getPos();
data.posX = Common::Util::floatToUInt16( pos.x );
data.posY = Common::Util::floatToUInt16( pos.y );
data.posZ = Common::Util::floatToUInt16( pos.z );
data.rotation = Common::Util::floatToUInt16Rot( m_pSource->getRot() );
m_pSource->sendToInRangeSet( castPacket, true );
player->setStateFlag( Common::PlayerStateFlag::Casting );
auto actionStartPkt = makeActorControlSelf( m_pSource->getId(), ActorControlType::ActionStart, 1, getId(), m_recastTimeMs / 10 );
player->queuePacket( actionStartPkt );
}
void MountAction::execute()
{
assert( m_pSource );
m_effectBuilder->mount( m_pSource, m_mountId );
m_effectBuilder->buildAndSendPackets();
}

View file

@ -0,0 +1,25 @@
#ifndef SAPPHIRE_MOUNTACTION_H
#define SAPPHIRE_MOUNTACTION_H
#include "Action.h"
namespace Sapphire::World::Action
{
class MountAction : public Action
{
public:
MountAction( Entity::CharaPtr source, uint32_t mountId, uint16_t sequence, Data::ActionPtr actionData, FrameworkPtr fw );
virtual ~MountAction() = default;
bool preCheck() override;
void start() override;
void execute() override;
private:
uint32_t m_mountId;
};
}
#endif //SAPPHIRE_MOUNTACTION_H

View file

@ -87,6 +87,7 @@ namespace World::Action
TYPE_FORWARD( Action );
TYPE_FORWARD( EventAction );
TYPE_FORWARD( ItemAction );
TYPE_FORWARD( MountAction );
TYPE_FORWARD( EffectBuilder );
TYPE_FORWARD( EffectResult );

View file

@ -2,6 +2,7 @@
#include "Action/Action.h"
#include "Action/ItemAction.h"
#include "Action/MountAction.h"
#include "Script/ScriptMgr.h"
#include "Actor/Player.h"
@ -80,6 +81,22 @@ void World::Manager::ActionMgr::handleItemAction( Sapphire::Entity::Player& play
action->start();
}
void World::Manager::ActionMgr::handleMountAction( Entity::Player& player, uint32_t mountId,
Data::ActionPtr actionData, uint64_t targetId,
uint16_t sequence )
{
player.sendDebug( "mount: {0}", mountId );
auto action = Action::make_MountAction( player.getAsPlayer(), mountId, sequence, actionData, framework() );
action->setTargetId( targetId );
if( !action->init() )
return;
bootstrapAction( player, action, *actionData );
}
void World::Manager::ActionMgr::bootstrapAction( Entity::Player& player,
Action::ActionPtr currentAction,
Data::Action& actionData )

View file

@ -29,6 +29,9 @@ namespace Sapphire::World::Manager
void handleItemAction( Entity::Player& player, uint32_t itemId, Data::ItemActionPtr itemActionData,
uint16_t itemSourceSlot, uint16_t itemSourceContainer );
void handleMountAction( Entity::Player& player, uint32_t mountId,
Data::ActionPtr actionData, uint64_t targetId, uint16_t sequence );
private:
void bootstrapAction( Entity::Player& player, Action::ActionPtr currentAction, Data::Action& actionData );

View file

@ -72,7 +72,9 @@ void Sapphire::Network::GameConnection::actionHandler( FrameworkPtr pFw,
case Common::SkillType::MountSkill:
{
auto action = exdData->get< Data::Action >( 4 );
assert( action );
actionMgr->handleMountAction( player, actionId, action, targetId, sequence );
break;
}
}

View file

@ -61,7 +61,8 @@ namespace Sapphire::Network::Packets::Server
memcpy( m_data.orchestrionMask, player.getOrchestrionBitmask(), sizeof( m_data.orchestrionMask ) );
memcpy( m_data.mountGuideMask, player.getMountGuideBitmask(), sizeof( m_data.mountGuideMask ) );
//memcpy( m_data.mountGuideMask, player.getMountGuideBitmask(), sizeof( m_data.mountGuideMask ) );
memset( m_data.mountGuideMask, 255, sizeof( m_data.mountGuideMask ) );
//memcpy( m_data.unlockBitmask, player.getUnlockBitmask(), sizeof( m_data.unlockBitmask ) );
memset( m_data.unlockBitmask, 255, sizeof( m_data.unlockBitmask ) );