mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-28 23:27:45 +00:00
commit
3aafea9edf
16 changed files with 156 additions and 12 deletions
|
@ -632,10 +632,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
|
||||
};
|
||||
|
||||
|
@ -1009,6 +1009,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;
|
||||
|
@ -1022,9 +1023,8 @@ namespace Sapphire::Network::Packets::Server
|
|||
unsigned char companionDefRank;
|
||||
unsigned char companionAttRank;
|
||||
unsigned char companionHealRank;
|
||||
unsigned char u19[2];
|
||||
unsigned char mountGuideMask[19];
|
||||
uint8_t unk1[9];
|
||||
unsigned char u19[8];
|
||||
unsigned char mountGuideMask[22];
|
||||
char name[32];
|
||||
unsigned char unknownOword[16];
|
||||
unsigned char unknownOw;
|
||||
|
|
|
@ -275,7 +275,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 );
|
||||
|
||||
|
@ -736,6 +736,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 ) );
|
||||
|
||||
|
|
|
@ -80,7 +80,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.
|
||||
|
|
|
@ -91,6 +91,13 @@ void EffectBuilder::applyStatusEffect( Entity::CharaPtr& target, uint16_t status
|
|||
moveToResultList( target, nextResult );
|
||||
}
|
||||
|
||||
void EffectBuilder::mount( Entity::CharaPtr& target, uint16_t mountId )
|
||||
{
|
||||
EffectResultPtr nextResult = make_EffectResult( target, getResultDelayMs() );
|
||||
nextResult->mount( mountId );
|
||||
moveToResultList( target, nextResult );
|
||||
}
|
||||
|
||||
void EffectBuilder::buildAndSendPackets()
|
||||
{
|
||||
auto targetCount = m_resolvedEffects.size();
|
||||
|
|
|
@ -28,6 +28,8 @@ namespace Sapphire::World::Action
|
|||
|
||||
void applyStatusEffect( Entity::CharaPtr& target, uint16_t statusId, uint8_t param );
|
||||
|
||||
void mount( Entity::CharaPtr& target, uint16_t mountId );
|
||||
|
||||
void buildAndSendPackets();
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <Util/Util.h>
|
||||
|
||||
#include "Actor/Chara.h"
|
||||
#include "Actor/Player.h"
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::World::Action;
|
||||
|
@ -84,6 +85,14 @@ void EffectResult::applyStatusEffect( uint16_t statusId, uint8_t param )
|
|||
m_type = Common::ActionEffectType::ApplyStatusEffect;
|
||||
}
|
||||
|
||||
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{};
|
||||
|
@ -121,6 +130,13 @@ void EffectResult::execute()
|
|||
break;
|
||||
}
|
||||
|
||||
case Common::ActionEffectType::Mount:
|
||||
{
|
||||
auto pPlayer = m_target->getAsPlayer();
|
||||
pPlayer->mount( m_value );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace Sapphire::World::Action
|
|||
void startCombo( uint16_t actionId );
|
||||
void comboSucceed();
|
||||
void applyStatusEffect( uint16_t statusId, uint8_t param );
|
||||
void mount( uint16_t moundId );
|
||||
|
||||
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, uint16_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, uint16_t mountId, uint16_t sequence, Data::ActionPtr actionData, FrameworkPtr fw );
|
||||
virtual ~MountAction() = default;
|
||||
|
||||
bool preCheck() override;
|
||||
|
||||
void start() override;
|
||||
|
||||
void execute() override;
|
||||
|
||||
private:
|
||||
uint16_t m_mountId;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //SAPPHIRE_MOUNTACTION_H
|
|
@ -1045,7 +1045,7 @@ namespace Sapphire::Entity
|
|||
uint8_t m_titleList[48];
|
||||
uint8_t m_howTo[34];
|
||||
uint8_t m_minions[40];
|
||||
uint8_t m_mountGuide[19];
|
||||
uint8_t m_mountGuide[22];
|
||||
uint8_t m_homePoint;
|
||||
uint8_t m_startTown;
|
||||
uint16_t m_townWarpFstFlags;
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -78,6 +79,22 @@ void World::Manager::ActionMgr::handleItemAction( Sapphire::Entity::Player& play
|
|||
action->start();
|
||||
}
|
||||
|
||||
void World::Manager::ActionMgr::handleMountAction( Entity::Player& player, uint16_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, uint16_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, static_cast< uint16_t >( actionId ), action, targetId, sequence );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue