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:
parent
faa763fdf7
commit
8d10a34174
16 changed files with 155 additions and 9 deletions
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ) );
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
68
src/world/Action/MountAction.cpp
Normal file
68
src/world/Action/MountAction.cpp
Normal 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();
|
||||
}
|
25
src/world/Action/MountAction.h
Normal file
25
src/world/Action/MountAction.h
Normal 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
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ) );
|
||||
|
|
Loading…
Add table
Reference in a new issue