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

Merge actor_rewrite

This commit is contained in:
Maru 2018-03-05 22:09:14 -03:00
commit 76ccca75a9
393 changed files with 18858 additions and 3472 deletions

4
.gitignore vendored
View file

@ -114,3 +114,7 @@ src/common/Version\.cpp
# generated script loader files
src/servers/sapphire_zone/Script/Scripts/*/ScriptLoader.cpp
# cotire generated files/folders
cotire/
*_cotire.cmake

View file

@ -31,6 +31,7 @@ set(LIBRARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/libraries")
include( "cmake/boost.cmake" )
include( "cmake/mysql.cmake" )
include( "cmake/compiler.cmake" )
include( "cmake/cotire.cmake" )
##############################
# Git #
@ -68,3 +69,4 @@ add_subdirectory("src/tools/exd_struct_gen")
add_subdirectory("src/tools/exd_struct_test")
add_subdirectory("src/tools/quest_parser")
#add_subdirectory("src/tools/pcb_reader")
#add_subdirectory("src/tools/event_object_parser")

View file

@ -33,10 +33,10 @@ switch( commandId )
case 0x01: // Toggle sheathe
{
if ( param11 == 1 )
pPlayer->setStance( Entity::Actor::Stance::Active );
pPlayer->setStance( Entity::Chara::Stance::Active );
else
{
pPlayer->setStance( Entity::Actor::Stance::Passive );
pPlayer->setStance( Entity::Chara::Stance::Passive );
pPlayer->setAutoattack( false );
}

View file

@ -14,10 +14,10 @@ if(UNIX)
endif()
else()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../src/libraries/external/${SAPPHIRE_BOOST_FOLDER_NAME})
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/libraries/external/${SAPPHIRE_BOOST_FOLDER_NAME})
message(STATUS "Using boost in /libraries/external")
set(Boost_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/libraries/external/${SAPPHIRE_BOOST_FOLDER_NAME})
set(BOOST_LIBRARYDIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/libraries/external/${SAPPHIRE_BOOST_FOLDER_NAME}/lib32-msvc-14.0)
set(Boost_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/libraries/external/${SAPPHIRE_BOOST_FOLDER_NAME})
set(BOOST_LIBRARYDIR ${CMAKE_CURRENT_SOURCE_DIR}/src/libraries/external/${SAPPHIRE_BOOST_FOLDER_NAME}/lib32-msvc-14.0)
else()
find_package(Boost ${SAPPHIRE_BOOST_VER} COMPONENTS system)
if(Boost_FOUND)

View file

@ -21,6 +21,10 @@ else()
# incremental linking
message(STATUS "Enabling Incremental Linking..")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /INCREMENTAL")
# enable building with multiple processes
message(STATUS "Enabling Build with Multiple Processes..")
add_definitions(/MP)
endif()
endif()

4055
cmake/cotire.cmake Normal file

File diff suppressed because it is too large Load diff

View file

@ -16,6 +16,7 @@ namespace Core {
// 99 is the last spawn id that seems to spawn any actor
const uint8_t MAX_DISPLAYED_ACTORS = 99;
const uint8_t MAX_DISPLAYED_EOBJS = 40;
const int32_t INVALID_GAME_OBJECT_ID = 0xE0000000;
@ -403,71 +404,22 @@ namespace Core {
Gathering,
Fishing,
BeingRaised,
BetweenAreas,
Stealthed,
InnRoom,
Jumping,
AutoRun,
Occupied6,
BetweenAreas1,
SystemError,
LoggingOut,
enum PlayerStateFlag : uint8_t
{
HideUILockChar = 0, // as the name suggests, hides the ui and logs the char...
InCombat = 1, // in Combat, locks gearchange/return/teleport
Casting = 2,
InNpcEvent = 7, // when talking to an npc, locks ui giving "occupied" message
InvalidLocation,
WaitingForDuty,
BoundByDuty1,
Mounting,
WatchingCutscene,
WaitingForDutyFinder,
CreatingCharacter,
Jumping1,
PvpDisplay,
StatusAfflication2,
InNpcEvent1 = 10, // Sent together with InNpcEvent, when waiting for input? just a guess...
Mounting1,
CarryingItem,
UsingPartyFinder,
HousingFunctions,
Transformed,
FreeTrail,
BeingMoved,
Mounting2,
StatusAffliction3,
StatusAffliction4,
BetweenAreas = 24,
BoundByDuty = 28,
WatchingCutscene = 50, // this is actually just a dummy, this id is different
RegisteringRaceOrMatch,
WaitingForRaceOrMatch,
WaitingForTripleTriadMatch,
InFlight,
WatchingCutscene1,
DeepDungeon,
Swimming,
Diving,
RegisteringTripleTriad,
WaitingTripleTriad,
InCrossWorldParty
};
enum struct FateStatus : uint8_t
{
Active = 2,
Inactive = 4,
Preparing = 7,
Completed = 8,
};
enum ActorControlType : uint16_t
{
ToggleWeapon = 0x01,
SetStatus = 0x02,
CastStart = 0x03,
ToggleAggro = 0x04,
ClassJobChange = 0x05,
DefeatMsg = 0x06,
GainExpMsg = 0x07,
LevelUpEffect = 0x0A,
ExpChainMsg = 0x0C,
@ -778,13 +730,7 @@ namespace Core {
FreeCompany = 5,
};
enum SocialListType : uint8_t
{
PartyList = 0x02,
FriendList = 0x0b,
SearchList = 0x0e,
};
typedef std::vector< PlayerStateFlag > PlayerStateFlagList;
// todo: rename SocialRequestAction and SocialRequestResponse cause they seem ambiguous
enum class SocialRequestAction : uint8_t

View file

@ -463,6 +463,7 @@ namespace Common {
//Weather.exd
enum class Weather : uint8_t
{
None = 0,
ClearSkies = 1,
FairSkies = 2,
Clouds = 3,

View file

@ -172,6 +172,7 @@ Core::Data::Aetheryte::Aetheryte( uint32_t row_id, Core::Data::ExdDataGenerated*
placeName = exdData->getField< uint16_t >( row, 8 );
aethernetName = exdData->getField< uint16_t >( row, 9 );
territory = exdData->getField< uint16_t >( row, 10 );
levelId = exdData->getField< uint32_t >( row, 11 );
isAetheryte = exdData->getField< bool >( row, 15 );
aethernetGroup = exdData->getField< uint8_t >( row, 16 );
map = exdData->getField< uint16_t >( row, 19 );

View file

@ -496,6 +496,7 @@ struct Aetheryte
uint16_t placeName;
uint16_t aethernetName;
uint16_t territory;
uint32_t levelId;
bool isAetheryte;
uint8_t aethernetGroup;
uint16_t map;

View file

@ -72,8 +72,8 @@ namespace Packets {
Playtime = 0x00DF, // updated 4.2
CFRegistered = 0x00B8, // updated 4.1
SocialRequestResponse = 0x00BB, // updated 4.1
CancelAllianceForming = 0x00C6, // updated 4.2
Chat = 0x00E1, // updated 4.2
SocialRequestResponse = 0x00E5, // updated 4.1
SocialRequestReceive = 0x00E6, // updated 4.2
@ -104,15 +104,18 @@ namespace Packets {
NpcSpawn = 0x015D, // updated 4.2
ActorMove = 0x015E, // updated 4.2
ActorSetPos = 0x0160, // updated 4.2
ActorCast = 0x0162, // updated 4.2
HateList = 0x0165, // updated 4.2
ObjectSpawn = 0x0167, // updated 4.2
ObjectDespawn = 0x0168, // updated 4.2
UpdateClassInfo = 0x0169, // updated 4.2
InitUI = 0x016B, // updated 4.2
ActorOwner = 0x016D, // updated 4.2 ?
PlayerStats = 0x016C, // updated 4.2
ActorOwner = 0x016D, // updated 4.2 ?
PlayerStateFlags = 0x016E, // updated 4.2
PlayerClassInfo = 0x016F, // updated 4.2
ModelEquip = 0x0170, // updated 4.2
@ -127,6 +130,7 @@ namespace Packets {
UpdateInventorySlot = 0x0181, // updated 4.2
EventPlay = 0x018E, // updated 4.2
DirectorPlayScene = 0x0192, // updated 4.2
EventStart = 0x0198, // updated 4.2
EventFinish = 0x0199, // updated 4.2
@ -209,6 +213,8 @@ namespace Packets {
FcInfoReqHandler = 0x011A, // updated 4.2
ReqJoinNoviceNetwork = 0x0129, // updated 4.2
ReqCountdownInitiate = 0x012C, // updated 4.2
ReqCountdownCancel = 0x012D, // updated 4.2
@ -230,8 +236,8 @@ namespace Packets {
OutOfRangeEventHandler = 0x014B, // updated 4.2
EnterTeriEventHandler = 0x014C, // updated 4.2
ReturnEventHandler = 0x0151, // updated 4.2 ?
TradeReturnEventHandler = 0x0152, // updated 4.2 ?
ReturnEventHandler = 0x0151, // updated 4.2
TradeReturnEventHandler = 0x0152, // updated 4.2
LinkshellEventHandler = 0x0144, // updated 4.1 ??

View file

@ -233,7 +233,7 @@ struct FFXIVIpcLinkshellList : FFXIVIpcBasePacket<LinkshellList>
struct FFXIVIpcStatusEffectList : FFXIVIpcBasePacket<StatusEffectList>
{
uint8_t classId;
uint8_t classId1;
uint8_t level1;
uint16_t level;
uint32_t current_hp;
uint32_t max_hp;
@ -427,7 +427,7 @@ struct FFXIVIpcPlayerSpawn : FFXIVIpcBasePacket<PlayerSpawn>
uint8_t spawnIndex;
uint8_t state;
uint8_t persistantEmote;
uint8_t type;
uint8_t modelType; // modelType -> eventSystemDefine
uint8_t subtype;
uint8_t voice;
uint16_t u25c;
@ -459,8 +459,7 @@ struct FFXIVIpcPlayerSpawn : FFXIVIpcBasePacket<PlayerSpawn>
*/
struct FFXIVIpcNpcSpawn : FFXIVIpcBasePacket<NpcSpawn>
{
uint16_t title;
uint16_t u1b;
uint32_t gimmickId; // needs to be existing in the map, mob will snap to it
uint8_t u2b;
uint8_t u2ab;
uint8_t gmRank;
@ -503,7 +502,7 @@ struct FFXIVIpcNpcSpawn : FFXIVIpcBasePacket<NpcSpawn>
uint8_t spawnIndex;
uint8_t state;
uint8_t persistantEmote;
uint8_t type;
uint8_t modelType;
uint8_t subtype;
uint8_t voice;
uint16_t u25c;
@ -611,7 +610,7 @@ struct FFXIVIpcHateList : FFXIVIpcBasePacket<HateList>
struct FFXIVIpcUpdateClassInfo : FFXIVIpcBasePacket<UpdateClassInfo>
{
uint8_t classId;
uint8_t classId1;
uint8_t level1;
uint16_t level;
uint32_t nextLevelIndex;
uint32_t currentExp;
@ -674,7 +673,7 @@ struct FFXIVIpcInitUI : FFXIVIpcBasePacket<InitUI>
uint8_t namedayDay;
uint8_t cityState;
uint8_t homepoint;
uint8_t unknown26;
uint8_t unknown26; // 2 if "warrior of light"
uint8_t petHotBar;
uint8_t companionRank;
uint8_t companionStars;
@ -871,10 +870,8 @@ struct FFXIVIpcActorOwner : FFXIVIpcBasePacket<ActorOwner>
*/
struct FFXIVIpcPlayerStateFlags : FFXIVIpcBasePacket<PlayerStateFlags>
{
uint8_t flags[7];
uint8_t padding1[3];
uint32_t padding2;
uint16_t padding;
uint8_t flags[12];
uint32_t padding;
};
/**
@ -1047,7 +1044,7 @@ struct FFXIVIpcEventStart : FFXIVIpcBasePacket<EventStart>
/* 000D */ uint8_t param2;
/* 000E */ uint16_t padding;
/* 0010 */ uint32_t param3;
/* 0014 */ uint32_t padding1;
/* 0014 */ uint32_t contentId;
};
@ -1071,6 +1068,24 @@ struct FFXIVIpcEventPlay : FFXIVIpcBasePacket<EventPlay>
/**
* Structural representation of the packet sent by the server
* to play an event
*/
struct FFXIVIpcDirectorPlayScene : FFXIVIpcBasePacket<DirectorPlayScene>
{
uint64_t actorId;
uint32_t eventId;
uint16_t scene;
uint16_t padding;
uint32_t flags;
uint32_t param3;
uint8_t param4;
uint8_t padding1[3];
uint32_t param5;
uint8_t unknown[0x40];
};
/**
* Structural representation of the packet sent by the server
* to finish an event
*/
struct FFXIVIpcEventFinish : FFXIVIpcBasePacket<EventFinish>
@ -1363,24 +1378,33 @@ struct FFXIVIpcMSQTrackerComplete : FFXIVIpcBasePacket<MSQTrackerComplete>
struct FFXIVIpcObjectSpawn : FFXIVIpcBasePacket<ObjectSpawn>
{
uint8_t count;
uint8_t spawnIndex;
uint8_t objKind;
uint8_t unknown2;
uint8_t state;
uint8_t unknown3;
uint32_t objId;
uint32_t actorId;
uint32_t levelId;
uint32_t unknown10;
uint32_t someActorId14;
uint32_t hierachyId;
uint32_t unknown1C;
uint32_t unknown20;
uint32_t unknown24;
uint32_t unknown28;
uint32_t unknown2c;
uint32_t gimmickId;
float scale;
int16_t unknown20a;
uint16_t rotation;
int16_t unknown24a;
int16_t unknown24b;
uint16_t unknown28a;
int16_t unknown28c;
uint32_t unknown2C;
Common::FFXIVARR_POSITION3 position;
int16_t rotation;
int16_t unknown;
int16_t unknown3C;
int16_t unknown3E;
};
struct FFXIVIpcObjectDespawn : FFXIVIpcBasePacket<ObjectDespawn>
{
uint8_t spawnIndex;
uint8_t padding[7];
};

View file

@ -0,0 +1,109 @@
#ifndef SAPPHIRE_SPAWNINDEXALLOCATOR_H
#define SAPPHIRE_SPAWNINDEXALLOCATOR_H
#include <queue>
#include <unordered_map>
#include <type_traits>
namespace Core
{
namespace Util
{
template< typename T, typename ActorIdType = uint32_t >
class SpawnIndexAllocator
{
public:
static_assert( std::is_same< T, uint8_t >::value || std::is_same< T, uint16_t >::value ||
std::is_same< T, uint32_t >::value || std::is_same< T, uint64_t >::value,
"T must be uint8_t, uint16_t, uint32_t, uint64_t" );
SpawnIndexAllocator() :
m_maxSlotId( 0 ),
m_reserveFirstSlot( false )
{ }
void init( T maxSlotId, bool reserveFirstSlot = false )
{
m_maxSlotId = maxSlotId;
m_reserveFirstSlot = reserveFirstSlot;
setupQueue();
// todo: reserve max slot id in map to prevent any runtime reshashing
}
T freeUsedSpawnIndex( ActorIdType actorId )
{
auto it = m_actorIdToAllocatedMap.find( actorId );
if( it == m_actorIdToAllocatedMap.end() )
return 0;
auto index = it->second;
m_availableIds.push( index );
m_actorIdToAllocatedMap.erase( it );
return index;
}
T getNextFreeSpawnIndex( ActorIdType actorId )
{
assert( m_maxSlotId != 0 );
if( m_availableIds.empty() )
return getAllocFailId();
auto nextId = m_availableIds.front();
m_availableIds.pop();
m_actorIdToAllocatedMap[actorId] = nextId;
return nextId;
}
void freeAllSpawnIndexes()
{
setupQueue();
m_actorIdToAllocatedMap.clear();
}
bool isSpawnIndexValid( T spawnIndex )
{
return spawnIndex != getAllocFailId();
}
constexpr T getAllocFailId()
{
return static_cast< T >( -1 );
}
protected:
void setupQueue()
{
assert( m_maxSlotId != 0 );
while( !m_availableIds.empty() )
m_availableIds.pop();
uint32_t start = 0;
// slot 0 is reserved when used for spawning actors/players otherwise the local player actor spawnIndex
// will be used by another actor and despawn the local player
if( m_reserveFirstSlot )
start = 1;
for( uint32_t i = start; i < m_maxSlotId; i++ )
m_availableIds.push( i );
}
std::queue< T > m_availableIds;
std::unordered_map< ActorIdType, T > m_actorIdToAllocatedMap;
T m_maxSlotId;
bool m_reserveFirstSlot;
};
}
}
#endif //SAPPHIRE_SPAWNINDEXALLOCATOR_H

View file

@ -34,11 +34,11 @@ namespace Core
namespace Entity
{
class Actor;
class Chara;
class Player;
class BattleNpc;
typedef boost::shared_ptr<Actor> ActorPtr;
typedef boost::shared_ptr<Chara> ActorPtr;
typedef boost::shared_ptr<Player> PlayerPtr;
typedef boost::shared_ptr<BattleNpc> BattleNpcPtr;
}
@ -91,10 +91,10 @@ namespace Core
namespace Scripting
{
typedef std::function< void( Entity::Player&, uint32_t, uint16_t, uint16_t, uint16_t, uint16_t ) > EventReturnCallback;
using EventReturnCallback = std::function< void( Entity::Player&, uint32_t, uint16_t, uint16_t, uint16_t, uint16_t ) >;
}
typedef std::function< void( Entity::Player&, uint32_t, uint64_t ) > ActionCallback;
using ActionCallback = std::function< void( Entity::Player&, uint32_t, uint64_t ) >;
}

View file

@ -148,13 +148,13 @@ namespace Core {
{
std::vector< uint8_t > customize( 26 );
std::vector< uint8_t > howTo( 32 );
std::vector< uint8_t > aetherytes( 12 );
std::vector< uint8_t > discovery( 411 );
std::vector< uint8_t > howTo( 33 );
std::vector< uint8_t > aetherytes( 16 );
std::vector< uint8_t > discovery( 421 );
std::vector< uint8_t > questComplete( 396 );
std::vector< uint8_t > unlocks( 64 );
std::vector< uint8_t > mountGuide( 13 );
std::vector< uint8_t > orchestrion( 38 );
std::vector< uint8_t > mountGuide( 15 );
std::vector< uint8_t > orchestrion( 40 );
std::vector< uint8_t > modelEquip( 40 );
std::vector< uint8_t > questTracking8( 10 );
std::vector< int16_t > questTracking = { -1, -1, -1, -1, -1 };

View file

@ -22,7 +22,7 @@ Core::Common::HandleActionType Core::Action::Action::getHandleActionType() const
return m_handleActionType;
}
Core::Entity::ActorPtr Core::Action::Action::getTargetActor() const
Core::Entity::CharaPtr Core::Action::Action::getTargetChara() const
{
return m_pTarget;
}
@ -57,7 +57,7 @@ void Core::Action::Action::setCastTime( uint32_t castTime )
m_castTime = castTime;
}
Core::Entity::ActorPtr Core::Action::Action::getActionSource() const
Core::Entity::CharaPtr Core::Action::Action::getActionSource() const
{
return m_pSource;
}

View file

@ -18,7 +18,7 @@ namespace Action {
Common::HandleActionType getHandleActionType() const;
Entity::ActorPtr getTargetActor() const;
Entity::CharaPtr getTargetChara() const;
bool isInterrupted() const;
@ -32,7 +32,7 @@ namespace Action {
void setCastTime( uint32_t castTime );
Entity::ActorPtr getActionSource() const;
Entity::CharaPtr getActionSource() const;
virtual void onStart() {};
virtual void onFinish() {};
@ -48,8 +48,8 @@ namespace Action {
uint64_t m_startTime;
uint32_t m_castTime;
Entity::ActorPtr m_pSource;
Entity::ActorPtr m_pTarget;
Entity::CharaPtr m_pSource;
Entity::CharaPtr m_pTarget;
bool m_bInterrupt;

View file

@ -27,7 +27,7 @@ Core::Action::ActionCast::ActionCast()
m_handleActionType = Common::HandleActionType::Event;
}
Core::Action::ActionCast::ActionCast( Entity::ActorPtr pActor, Entity::ActorPtr pTarget, uint16_t actionId )
Core::Action::ActionCast::ActionCast( Entity::CharaPtr pActor, Entity::CharaPtr pTarget, uint16_t actionId )
{
m_startTime = 0;
m_id = actionId;
@ -84,7 +84,7 @@ void Core::Action::ActionCast::onInterrupt()
if( !m_pSource )
return;
m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::Occupied1 );
//m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::Occupied1 );
m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::Casting );
auto control = ActorControlPacket142( m_pSource->getId(), ActorControlType::CastInterrupt,

View file

@ -15,7 +15,7 @@ namespace Action {
ActionCast();
~ActionCast();
ActionCast( Entity::ActorPtr pActor, Entity::ActorPtr pTarget, uint16_t actionId );
ActionCast( Entity::CharaPtr pActor, Entity::CharaPtr pTarget, uint16_t actionId );
void onStart() override;
void onFinish() override;

View file

@ -1,8 +1,11 @@
#include <common/Util/Util.h>
#include <common/Util/UtilMath.h>
#include <common/Exd/ExdDataGenerated.h>
#include "ActionCollision.h"
#include "Actor/Actor.h"
#include "Actor/Chara.h"
#include "Actor/Player.h"
#include <cmath>
@ -31,7 +34,7 @@ bool ActionCollision::isActorApplicable( Actor& actor, TargetFilter targetFilter
case TargetFilter::Allies:
{
// todo: implement ally NPCs
actorApplicable = !actor.isBattleNpc();
// actorApplicable = !chara.isBattleNpc();
break;
}
case TargetFilter::Party:
@ -42,12 +45,12 @@ bool ActionCollision::isActorApplicable( Actor& actor, TargetFilter targetFilter
}
case TargetFilter::Enemies:
{
actorApplicable = actor.isBattleNpc();
//actorApplicable = chara.isBattleNpc();
break;
}
}
return ( actorApplicable && actor.isAlive() );
return ( actorApplicable && actor.getAsChara()->isAlive() );
}
std::set< Core::Entity::ActorPtr > ActionCollision::getActorsHitFromAction( FFXIVARR_POSITION3 aoePosition,

View file

@ -2,12 +2,14 @@
#define _ACTIONCOLLISION_H
#include <common/Common.h>
#include <common/Exd/ExdDataGenerated.h>
#include "Actor/Actor.h"
#include "Action.h"
namespace Core {
namespace Data
{
struct Action;
}
namespace Entity {
enum class TargetFilter

View file

@ -25,7 +25,7 @@ Core::Action::ActionMount::ActionMount()
m_handleActionType = HandleActionType::Event;
}
Core::Action::ActionMount::ActionMount( Entity::ActorPtr pActor, uint16_t mountId )
Core::Action::ActionMount::ActionMount( Entity::CharaPtr pActor, uint16_t mountId )
{
m_startTime = 0;
m_id = mountId;
@ -79,7 +79,7 @@ void Core::Action::ActionMount::onFinish()
effectPacket.data().unknown_62 = 13;
effectPacket.data().actionTextId = 4;
effectPacket.data().numEffects = 1;
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( pPlayer->getRotation() );
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( pPlayer->getRot() );
effectPacket.data().effectTarget = INVALID_GAME_OBJECT_ID;
effectPacket.data().effects[0].effectType = ActionEffectType::Mount;
effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::CritDamage;
@ -95,7 +95,7 @@ void Core::Action::ActionMount::onInterrupt()
if( !m_pSource )
return;
m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::Occupied1 );
//m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::Occupied1 );
m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::Casting );
auto control = ActorControlPacket142( m_pSource->getId(), ActorControlType::CastInterrupt,

View file

@ -15,7 +15,7 @@ namespace Action {
ActionMount();
~ActionMount();
ActionMount( Entity::ActorPtr pActor, uint16_t mountId );
ActionMount( Entity::CharaPtr pActor, uint16_t mountId );
void onStart() override;
void onFinish() override;

View file

@ -22,7 +22,7 @@ Core::Action::ActionTeleport::ActionTeleport()
m_handleActionType = HandleActionType::Event;
}
Core::Action::ActionTeleport::ActionTeleport( Entity::ActorPtr pActor, uint16_t targetZone, uint16_t cost )
Core::Action::ActionTeleport::ActionTeleport( Entity::CharaPtr pActor, uint16_t targetZone, uint16_t cost )
{
m_startTime = 0;
m_id = 5;
@ -89,7 +89,7 @@ void Core::Action::ActionTeleport::onFinish()
effectPacket.data().actionTextId = 5;
effectPacket.data().unknown_5 = 1;
effectPacket.data().numEffects = 1;
effectPacket.data().rotation = static_cast< uint16_t >( 0x8000 * ( ( pPlayer->getRotation() + 3.1415926 ) ) / 3.1415926 );
effectPacket.data().rotation = static_cast< uint16_t >( 0x8000 * ( ( pPlayer->getRot() + 3.1415926 ) ) / 3.1415926 );
effectPacket.data().effectTarget = pPlayer->getId();
pPlayer->sendToInRangeSet( effectPacket, true );

View file

@ -17,7 +17,7 @@ namespace Action {
ActionTeleport();
~ActionTeleport();
ActionTeleport( Entity::ActorPtr pActor, uint16_t action, uint16_t cost );
ActionTeleport( Entity::CharaPtr pActor, uint16_t action, uint16_t cost );
void onStart() override;
void onFinish() override;

View file

@ -23,7 +23,7 @@ Core::Action::EventAction::EventAction()
m_handleActionType = HandleActionType::Event;
}
Core::Action::EventAction::EventAction( Entity::ActorPtr pActor, uint32_t eventId, uint16_t action,
Core::Action::EventAction::EventAction( Entity::CharaPtr pActor, uint32_t eventId, uint16_t action,
ActionCallback finishRef, ActionCallback interruptRef, uint64_t additional )
{
m_additional = additional;
@ -55,7 +55,8 @@ void Core::Action::EventAction::onStart()
if( m_pSource->isPlayer() )
{
m_pSource->sendToInRangeSet( control, true );
m_pSource->getAsPlayer()->setStateFlag( PlayerStateFlag::Occupied2 );
if( m_pSource->getAsPlayer()->hasStateFlag( PlayerStateFlag::InNpcEvent ) )
m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::InNpcEvent );
}
else
m_pSource->sendToInRangeSet( control );
@ -84,7 +85,7 @@ void Core::Action::EventAction::onFinish()
if( m_pSource->isPlayer() )
{
m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::Occupied2 );
//m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::Occupied2 );
m_pSource->sendToInRangeSet( control, true );
}
else
@ -112,8 +113,8 @@ void Core::Action::EventAction::onInterrupt()
{
auto control1 = ActorControlPacket143( m_pSource->getId(), ActorControlType::FreeEventPos, m_eventId );
m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::NoCombat );
m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::Occupied1 );
//m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::NoCombat );
//m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::Occupied1 );
m_pSource->sendToInRangeSet( control );
m_pSource->sendToInRangeSet( control1 );

View file

@ -16,7 +16,7 @@ namespace Action {
EventAction();
~EventAction();
EventAction( Entity::ActorPtr pActor, uint32_t eventId, uint16_t action,
EventAction( Entity::CharaPtr pActor, uint32_t eventId, uint16_t action,
ActionCallback finishRef, ActionCallback interruptRef, uint64_t additional );
void onStart() override;

View file

@ -24,7 +24,7 @@ Core::Action::EventItemAction::EventItemAction()
m_handleActionType = HandleActionType::Event;
}
Core::Action::EventItemAction::EventItemAction( Entity::ActorPtr pActor, uint32_t eventId, uint16_t action,
Core::Action::EventItemAction::EventItemAction( Entity::CharaPtr pActor, uint32_t eventId, uint16_t action,
ActionCallback finishRef, ActionCallback interruptRef, uint64_t additional )
{
m_additional = additional;
@ -75,7 +75,7 @@ void Core::Action::EventItemAction::onFinish()
effectPacket.data().actionTextId = m_id;
effectPacket.data().unknown_5 = 2;
effectPacket.data().numEffects = 1;
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( m_pSource->getRotation() );
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( m_pSource->getRot() );
effectPacket.data().effectTarget = static_cast< uint32_t >( m_additional );
m_pSource->getAsPlayer()->unsetStateFlag( Common::PlayerStateFlag::Casting );

View file

@ -14,7 +14,7 @@ namespace Action {
EventItemAction();
~EventItemAction();
EventItemAction( Entity::ActorPtr pActor, uint32_t eventId, uint16_t action,
EventItemAction( Entity::CharaPtr pActor, uint32_t eventId, uint16_t action,
ActionCallback finishRef, ActionCallback interruptRef, uint64_t additional );
void onStart() override;

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,10 @@
#ifndef _ACTOR_H_
#define _ACTOR_H_
#ifndef _GAME_OBJECT_H_
#define _GAME_OBJECT_H_
#include <common/Common.h>
#include <boost/enable_shared_from_this.hpp>
#include "Forwards.h"
#include "GameObject.h"
#include <set>
#include <map>
#include <queue>
@ -14,247 +13,86 @@ namespace Core {
namespace Entity {
/*!
\class Actor
\brief Base class for all actors
\class GameObject
\brief Base class for all actor/objects
*/
class Actor : public GameObject
class Actor : public boost::enable_shared_from_this< Actor >
{
public:
enum Stance : uint8_t
enum ObjKind : uint8_t
{
Passive = 0,
Active = 1,
None = 0x00,
Player = 0x01,
BattleNpc = 0x02,
EventNpc = 0x03,
Treasure = 0x04,
Aetheryte = 0x05,
GatheringPoint = 0x06,
EventObj = 0x07,
Mount = 0x08,
Companion = 0x09, // this probably actually means minion
Retainer = 0x0A,
Area = 0x0B,
Housing = 0x0C,
Cutscene = 0x0D,
CardStand = 0x0E,
};
enum DisplayFlags : uint16_t
{
ActiveStance = 0x001,
Invisible = 0x020,
HideHead = 0x040,
HideWeapon = 0x080,
Faded = 0x100,
Visor = 0x800,
};
enum struct ActorStatus : uint8_t
{
Idle = 0x01,
Dead = 0x02,
Sitting = 0x03,
Mounted = 0x04,
Crafting = 0x05,
Gathering = 0x06,
Melding = 0x07,
SMachine = 0x08
};
struct ActorStats
{
uint32_t max_mp = 0;
uint32_t max_hp = 0;
uint32_t str = 0;
uint32_t dex = 0;
uint32_t vit = 0;
uint32_t inte = 0;
uint32_t mnd = 0;
uint32_t pie = 0;
uint32_t tenacity = 0;
uint32_t attack = 0;
uint32_t defense = 0;
uint32_t accuracy = 0;
uint32_t spellSpeed = 0;
uint32_t magicDefense = 0;
uint32_t critHitRate = 0;
uint32_t resistSlash = 0;
uint32_t resistPierce = 0;
uint32_t resistBlunt = 0;
uint32_t attackPotMagic = 0;
uint32_t healingPotMagic = 0;
uint32_t determination = 0;
uint32_t skillSpeed = 0;
uint32_t resistSlow = 0;
uint32_t resistSilence = 0;
uint32_t resistBlind = 0;
uint32_t resistPoison = 0;
uint32_t resistStun = 0;
uint32_t resistSleep = 0;
uint32_t resistBind = 0;
uint32_t resistHeavy = 0;
uint32_t resistFire = 0;
uint32_t resistIce = 0;
uint32_t resistWind = 0;
uint32_t resistEarth = 0;
uint32_t resistLightning = 0;
uint32_t resistWater = 0;
} m_baseStats;
protected:
char m_name[34];
/*! Position of the object */
Common::FFXIVARR_POSITION3 m_pos;
/*! Rotation of the object */
float m_rot;
/*! Id of the actor */
uint32_t m_id;
/*! Type of the actor */
ObjKind m_objKind;
/*! Id of the zone the actor currently is in */
uint32_t m_zoneId;
/*! Ptr to the ZoneObj the actor belongs to */
ZonePtr m_pCurrentZone;
/*! Last tick time for the actor ( in ms ) */
uint64_t m_lastTickTime;
/*! Last time the actor performed an autoAttack ( in ms ) */
uint64_t m_lastAttack;
/*! Last time the actor was updated ( in ms ) */
uint64_t m_lastUpdate;
/*! Current stance of the actor */
Stance m_currentStance;
/*! Current staus of the actor */
ActorStatus m_status;
/*! Max HP of the actor ( based on job / class ) */
uint32_t m_maxHp;
/*! Max MP of the actor ( based on job / class ) */
uint32_t m_maxMp;
/*! Current HP of the actor */
uint32_t m_hp;
/*! Current MP of the actor */
uint32_t m_mp;
/*! Current TP of the actor */
uint16_t m_tp;
/*! Current GP of the actor */
uint16_t m_gp;
/*! Additional look info of the actor */
uint8_t m_customize[26];
/*! Current class of the actor */
Common::ClassJob m_class;
/*! Id of the currently selected target actor */
uint64_t m_targetId;
/*! Ptr to a queued action */
Action::ActionPtr m_pCurrentAction;
/*! Invincibility type */
Common::InvincibilityType m_invincibilityType;
/*! Status effects */
const uint8_t MAX_STATUS_EFFECTS = 30;
std::queue< uint8_t > m_statusEffectFreeSlotQueue;
std::vector< std::pair< uint8_t, uint32_t> > m_statusEffectList;
std::map< uint8_t, StatusEffect::StatusEffectPtr > m_statusEffectMap;
std::set< ActorPtr > m_inRangeActors;
/*! list of various actors in range */
std::set< ActorPtr > m_inRangeActor;
std::set< PlayerPtr > m_inRangePlayers;
/*! Parent cell in the zone */
Core::Cell* m_pCell;
public:
Actor( ObjKind type );
explicit Actor( ObjKind type );
virtual ~Actor() {};
virtual ~Actor() override;
virtual void spawn( PlayerPtr pTarget ) {}
virtual void despawn( PlayerPtr pTarget ) {}
virtual void calculateStats() {};
uint32_t getId() const;
void setId( uint32_t id );
/// Status effect functions
void addStatusEffect( StatusEffect::StatusEffectPtr pEffect );
void removeStatusEffect( uint8_t effectSlotId );
void removeSingleStatusEffectById( uint32_t id );
void updateStatusEffects();
ObjKind getObjKind() const;
bool hasStatusEffect( uint32_t id );
Common::FFXIVARR_POSITION3& getPos();
void setPos( const Common::FFXIVARR_POSITION3& pos );
void setPos( float x, float y, float z );
int8_t getStatusEffectFreeSlot();
void statusEffectFreeSlot( uint8_t slotId );
float getRot() const;
void setRot( float rot );
std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > getStatusEffectMap() const;
void sendStatusEffectUpdate();
// add a status effect by id
void addStatusEffectById( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param = 0 );
// add a status effect by id if it doesn't exist
void addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param = 0 );
// remove a status effect by id
void removeSingleStatusEffectFromId( uint32_t id );
/// End Status Effect Functions
void setPosition( const Common::FFXIVARR_POSITION3& pos );
void setPosition( float x, float y, float z );
void setRotation( float rot );
float getRotation() const;
std::string getName() const;
std::set< ActorPtr > getInRangeActors( bool includeSelf = false );
bool face( const Common::FFXIVARR_POSITION3& p );
Stance getStance() const;
void setStance( Stance stance );
ActorStats getStats() const;
uint32_t getHp() const;
uint32_t getMp() const;
uint16_t getTp() const;
uint16_t getGp() const;
Common::InvincibilityType getInvincibilityType() const;
Common::ClassJob getClass() const;
uint8_t getClassAsInt() const;
void setClass( Common::ClassJob classJob );
void setTargetId( uint64_t targetId );
uint64_t getTargetId() const;
bool isAlive() const;
virtual uint32_t getMaxHp() const;
virtual uint32_t getMaxMp() const;
void resetHp();
void resetMp();
void setHp( uint32_t hp );
void setMp( uint32_t mp );
void setGp( uint32_t gp );
void setInvincibilityType( Common::InvincibilityType type );
void die();
ActorStatus getStatus() const;
void setStatus( ActorStatus status );
void handleScriptSkill( uint32_t type, uint16_t actionId, uint64_t param1, uint64_t param2, Entity::Actor& target );
virtual void autoAttack( ActorPtr pTarget );
bool isChara() const;
bool isPlayer() const;
bool isEventNpc() const;
bool isBattleNpc() const;
bool isRetainer() const;
bool isCompanion() const;
bool isEventObj() const;
bool isHousingEventObj() const;
bool isAetheryte() const;
///// IN RANGE LOGIC ///////////////////////////////
virtual void onRemoveInRangeActor( Actor& pActor ) {}
virtual void onDeath() {};
virtual void onDamageTaken( Actor& pSource ) {};
virtual void onActionHostile( Actor& source ) {};
virtual void onActionFriendly( Actor& pSource ) {};
virtual void onTick() {};
virtual void changeTarget( uint64_t targetId );
virtual uint8_t getLevel() const;
virtual void sendStatusUpdate( bool toSelf = true );
virtual void takeDamage( uint32_t damage );
virtual void heal( uint32_t amount );
virtual bool checkAction();
virtual void update( int64_t currTime ) {};
Action::ActionPtr getCurrentAction() const;
void setCurrentAction( Action::ActionPtr pAction );
///// IN RANGE LOGIC /////
// check if another actor is in the actors in range set
bool isInRangeSet( ActorPtr pActor ) const;
@ -266,30 +104,34 @@ public:
void addInRangeActor( ActorPtr pActor );
// remove an actor from the in range set
void removeInRangeActor( Actor& pActor );
void removeInRangeActor( Actor& actor );
// return true if there is at least one actor in the in range set
bool hasInRangeActor() const;
void checkInRangeActors();
void removeFromInRange();
// clear the whole in range set, this does no cleanup
virtual void clearInRangeSet();
ZonePtr getCurrentZone() const;
std::set< ActorPtr > getInRangeActors( bool includeSelf = false );
////////////////////////////////////////////////////
CharaPtr getAsChara();
PlayerPtr getAsPlayer();
EventObjectPtr getAsEventObj();
ZonePtr getCurrentZone() const;
void setCurrentZone( ZonePtr currZone );
// get the current cell of a region the actor is in
Cell* getCell() const;
InstanceContentPtr getCurrentInstance() const;
// get the current cell of a region the actor is in
Cell* getCellPtr();
// set the current cell
void setCell( Cell* pCell );
Core::Cell* m_pCell;
};
}

View file

@ -1,569 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
#include <cmath>
#include <common/Logging/Logger.h>
#include <common/Exd/ExdDataGenerated.h>
#include <common/Util/Util.h>
#include <common/Util/UtilMath.h>
#include "Network/PacketWrappers/MoveActorPacket.h"
#include "Network/PacketWrappers/ActorControlPacket142.h"
#include "Network/PacketWrappers/ActorControlPacket143.h"
#include "Player.h"
#include "BattleNpc.h"
#include "Framework.h"
using namespace Core::Common;
using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;
extern Core::Framework g_framework;
uint32_t Core::Entity::BattleNpc::m_nextID = 1149241694;
Core::Entity::BattleNpc::BattleNpc() :
Actor( ObjKind::BattleNpc )
{
m_id = 0;
m_status = ActorStatus::Idle;
}
Core::Entity::BattleNpc::~BattleNpc()
{
}
Core::Entity::BattleNpc::BattleNpc( uint16_t modelId, uint16_t nameid, const Common::FFXIVARR_POSITION3& spawnPos,
uint16_t bnpcBaseId, uint32_t type, uint8_t level, uint8_t behaviour,
uint32_t mobType ) :
Actor( ObjKind::BattleNpc )
{
BattleNpc::m_nextID++;
m_id = BattleNpc::m_nextID;
//strcpy( m_name, pBNpc->m_name.c_str() );
m_pos = spawnPos;
m_posOrigin = spawnPos;
m_mode = MODE_IDLE;
m_targetId = static_cast< uint64_t >( INVALID_GAME_OBJECT_ID );
m_maxHp = 150;
m_maxMp = 100;
m_baseStats.max_hp = m_maxHp;
m_baseStats.max_mp = m_maxMp;
m_hp = m_maxHp;
m_mp = m_maxMp;
m_currentStance = Stance::Passive;
m_class = ClassJob::Gladiator;
m_level = level > uint8_t{0} ? level : uint8_t{70};
m_modelId = modelId;
m_nameId = nameid;
m_behavior = behaviour;
m_bnpcBaseId = bnpcBaseId;
m_status = ActorStatus::Idle;
m_pOwner = nullptr;
m_mobType = mobType;
m_invincibilityType = InvincibilityType::InvincibilityNone;
//m_type = static_cast< Common::ObjKind >( type );
}
// spawn this player for pTarget
void Core::Entity::BattleNpc::spawn( PlayerPtr pTarget )
{
//GamePacketNew< FFXIVIpcActorSpawn > spawnPacket( getId(), pTarget->getId() );
//spawnPacket.data().unknown_0 = 0;
//spawnPacket.data().ownerId = m_pOwner == nullptr ? INVALID_GAME_OBJECT_ID : m_pOwner->getId();
//spawnPacket.data().targetId = INVALID_GAME_OBJECT_ID & 0xFFFFFFFF;
//spawnPacket.data().hPCurr = m_hp;
//spawnPacket.data().hPMax = m_baseStats.max_hp;
//spawnPacket.data().level = m_level;
////spawnPacket.data().tPCurr = 1000;
//spawnPacket.data().model = m_modelId;
//spawnPacket.data().bnpcBaseId = m_bnpcBaseId;
//spawnPacket.data().nameId = m_nameId;
//spawnPacket.data().spawnIndex = pTarget->getSpawnIdForActorId( getId() );
//g_framework.getLogger().info(std::to_string(spawnPacket.data().spawnIndex) + " " + std::to_string(getId()));
//spawnPacket.data().status = static_cast< uint8_t >( m_status );
//spawnPacket.data().mobAgressive = m_behavior;
//spawnPacket.data().type = static_cast< uint8_t >( m_type );
//spawnPacket.data().mobTypeIcon = m_mobType;
//spawnPacket.data().unknown_33 = 5;
//spawnPacket.data().typeFlags = 4;
//spawnPacket.data().pos.x = m_pos.x;
//spawnPacket.data().pos.y = m_pos.y;
//spawnPacket.data().pos.z = m_pos.z;
//spawnPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() );
////spawnPacket.data().unknown_B0[11] = 1;
////spawnPacket.data().unknown_B0[12] = 4;
////spawnPacket.data().unknown_B0[14] = 20;
//pTarget->queuePacket( spawnPacket );
ZoneChannelPacket< FFXIVIpcNpcSpawn > spawnPacket( getId(), pTarget->getId() );
spawnPacket.data().pos.x = m_pos.x;
spawnPacket.data().pos.y = m_pos.y;
spawnPacket.data().pos.z = m_pos.z;
spawnPacket.data().targetId = INVALID_GAME_OBJECT_ID & 0xFFFFFFFF;
spawnPacket.data().hPCurr = m_hp;
spawnPacket.data().hPMax = m_baseStats.max_hp;
spawnPacket.data().level = m_level;
spawnPacket.data().subtype = 5;
spawnPacket.data().enemyType = 4;
spawnPacket.data().modelChara = m_modelId;
spawnPacket.data().bNPCBase = m_bnpcBaseId;
spawnPacket.data().bNPCName = m_nameId;
spawnPacket.data().spawnIndex = pTarget->getSpawnIdForActorId( getId() );
spawnPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() );
spawnPacket.data().type = static_cast< uint8_t >( m_objKind );
spawnPacket.data().state = static_cast< uint8_t >( m_status );
pTarget->queuePacket( spawnPacket );
}
// despawn
void Core::Entity::BattleNpc::despawn( PlayerPtr pPlayer )
{
pPlayer->freePlayerSpawnId( getId() );
ActorControlPacket143 controlPacket( m_id, DespawnZoneScreenMsg, 0x04, getId(), 0x01 );
pPlayer->queuePacket( controlPacket );
}
uint8_t Core::Entity::BattleNpc::getLevel() const
{
return m_level;
}
Core::Entity::StateMode Core::Entity::BattleNpc::getMode() const
{
return m_mode;
}
void Core::Entity::BattleNpc::setMode( StateMode mode )
{
m_mode = mode;
}
uint8_t Core::Entity::BattleNpc::getbehavior() const
{
return m_behavior;
}
void Core::Entity::BattleNpc::hateListAdd( Actor& actor, int32_t hateAmount )
{
auto hateEntry = new HateListEntry();
hateEntry->m_hateAmount = hateAmount;
hateEntry->m_pActor = actor.getAsActor();
m_hateList.insert( hateEntry );
}
Core::Entity::ActorPtr Core::Entity::BattleNpc::hateListGetHighest()
{
auto it = m_hateList.begin();
uint32_t maxHate = 0;
HateListEntry* entry = nullptr;
for( ; it != m_hateList.end(); ++it )
{
if( ( *it )->m_hateAmount > maxHate )
{
maxHate = ( *it )->m_hateAmount;
entry = *it;
}
}
if( entry && maxHate != 0 )
return entry->m_pActor;
return nullptr;
}
void Core::Entity::BattleNpc::setOwner( PlayerPtr pPlayer )
{
m_pOwner = pPlayer;
if( pPlayer != nullptr )
{
ZoneChannelPacket< FFXIVIpcActorOwner > setOwnerPacket( getId(), pPlayer->getId() );
setOwnerPacket.data().type = 0x01;
setOwnerPacket.data().actorId = pPlayer->getId();
sendToInRangeSet( setOwnerPacket );
}
else
{
ZoneChannelPacket< FFXIVIpcActorOwner > setOwnerPacket(getId(), INVALID_GAME_OBJECT_ID );
setOwnerPacket.data().type = 0x01;
setOwnerPacket.data().actorId = INVALID_GAME_OBJECT_ID;
sendToInRangeSet( setOwnerPacket );
}
}
void Core::Entity::BattleNpc::sendPositionUpdate()
{
MoveActorPacket movePacket( *this, 0x3A, 0x00, 0, 0x5A );
sendToInRangeSet( movePacket );
}
bool Core::Entity::BattleNpc::moveTo( Common::FFXIVARR_POSITION3& pos )
{
if( Math::Util::distance( getPos().x, getPos().y, getPos().z,
pos.x, pos.y, pos.z ) <= 4 )
// reached destination
return true;
float rot = Math::Util::calcAngFrom( getPos().x, getPos().z, pos.x, pos.z );
float newRot = PI - rot + ( PI / 2 );
face( pos );
float angle = Math::Util::calcAngFrom( getPos().x, getPos().z, pos.x, pos.z ) + PI;
float x = static_cast< float >( cosf( angle ) * 1.1f );
float y = ( getPos().y + pos.y ) * 0.5f; // fake value while there is no collision
float z = static_cast< float >( sinf( angle ) * 1.1f );
Common::FFXIVARR_POSITION3 newPos{};
newPos.x = getPos().x + x;
newPos.y = y;
newPos.z = getPos().z + z;
setPosition( newPos );
Common::FFXIVARR_POSITION3 tmpPos{};
tmpPos.x = getPos().x + x;
tmpPos.y = y;
tmpPos.z = getPos().z + z;
setPosition( tmpPos );
setRotation(newRot);
sendPositionUpdate();
return false;
}
void Core::Entity::BattleNpc::aggro( Actor& actor )
{
m_lastAttack = Util::getTimeMs();
hateListUpdate( actor, 1 );
changeTarget( actor.getId() );
setStance( Stance::Active );
m_mode = MODE_COMBAT;
if( actor.isPlayer() )
{
PlayerPtr tmpPlayer = actor.getAsPlayer();
tmpPlayer->queuePacket( ActorControlPacket142( getId(), 0, 1, 1 ) );
tmpPlayer->onMobAggro( getAsBattleNpc() );
}
}
void Core::Entity::BattleNpc::deaggro( Actor& actor )
{
if( !hateListHasActor( actor ) )
hateListRemove( actor );
if( actor.isPlayer() )
{
PlayerPtr tmpPlayer = actor.getAsPlayer();
tmpPlayer->onMobDeaggro( getAsBattleNpc() );
}
}
void Core::Entity::BattleNpc::hateListClear()
{
auto it = m_hateList.begin();
for( ; it != m_hateList.end(); ++it )
{
if( isInRangeSet( ( *it )->m_pActor ) )
deaggro( *( *it )->m_pActor );
HateListEntry* tmpListEntry = ( *it );
delete tmpListEntry;
}
m_hateList.clear();
}
void Core::Entity::BattleNpc::hateListRemove( Actor& actor )
{
auto it = m_hateList.begin();
for( ; it != m_hateList.end(); ++it )
{
if( ( *it )->m_pActor->getId() == actor.getId() )
{
HateListEntry* pEntry = *it;
m_hateList.erase( it );
delete pEntry;
if( actor.isPlayer() )
{
PlayerPtr tmpPlayer = actor.getAsPlayer();
tmpPlayer->onMobDeaggro( getAsBattleNpc() );
}
return;
}
}
}
bool Core::Entity::BattleNpc::hateListHasActor( Actor& actor )
{
auto it = m_hateList.begin();
for( ; it != m_hateList.end(); ++it )
{
if( ( *it )->m_pActor->getId() == actor.getId() )
return true;
}
return false;
}
void Core::Entity::BattleNpc::resetPos()
{
m_pos = m_posOrigin;
}
uint32_t Core::Entity::BattleNpc::getNameId() const
{
return m_nameId;
}
void Core::Entity::BattleNpc::hateListUpdate( Actor& actor, int32_t hateAmount )
{
auto it = m_hateList.begin();
for( ; it != m_hateList.end(); ++it )
{
if( ( *it )->m_pActor->getId() == actor.getId() )
{
( *it )->m_hateAmount += hateAmount;
return;
}
}
auto hateEntry = new HateListEntry();
hateEntry->m_hateAmount = hateAmount;
hateEntry->m_pActor = actor.getAsActor();
m_hateList.insert( hateEntry );
}
void Core::Entity::BattleNpc::onDeath()
{
//LuaManager->onMobDeath( this );
setTimeOfDeath( static_cast< uint32_t >( time( nullptr ) ) );
setTargetId( INVALID_GAME_OBJECT_ID );
m_currentStance = Stance::Passive;
m_mode = MODE_IDLE;
m_hp = 0;
setOwner( nullptr );
// todo: fully ghetto retarded exp reward pls fix
{
uint32_t minHate = -1;
uint32_t maxHate = 0;
uint32_t totalHate = 0;
for( auto& pHateEntry : m_hateList )
{
if( pHateEntry->m_pActor->isPlayer() )
{
if( pHateEntry->m_hateAmount < minHate )
minHate = pHateEntry->m_hateAmount;
else if( pHateEntry->m_hateAmount > maxHate )
maxHate = pHateEntry->m_hateAmount;
}
totalHate += pHateEntry->m_hateAmount;
}
//uint32_t plsBeHatedThisMuchAtLeast = totalHate / ( maxHate + 2 ) / clamp( m_hateList.size(), 1.0f, 1.5f );
for( auto& pHateEntry : m_hateList )
{
// todo: this is pure retarded
// todo: check for companion
if( pHateEntry->m_pActor->isPlayer() ) // && pHateEntry->m_hateAmount >= plsBeHatedThisMuchAtLeast )
{
uint8_t level = pHateEntry->m_pActor->getLevel();
auto levelDiff = static_cast< int32_t >( this->m_level ) - level;
auto cappedLevelDiff = Math::Util::clamp( levelDiff, 1, 6 );
auto expNeeded = g_framework.getExdDataGen().get< Core::Data::ParamGrow >( m_level + cappedLevelDiff - 1 )->expToNext;
int32_t exp = 0;
// todo: arbitrary numbers pulled out of my ass
if( m_level <= 14 )
exp = ( expNeeded / ( 100 - levelDiff) ) + cappedLevelDiff + ( cappedLevelDiff * ( ( rand() % ( cappedLevelDiff * 9 ) ) + 1 ) );
else if( m_level <= 24 )
exp = ( expNeeded / ( 150 - levelDiff) ) + cappedLevelDiff + ( cappedLevelDiff * ( ( rand() % ( cappedLevelDiff * 8 ) ) + 1 ) );
else if( m_level <= 34 )
exp = ( expNeeded / ( 350 - levelDiff ) ) + cappedLevelDiff + ( cappedLevelDiff * ( ( rand() % ( cappedLevelDiff * 7 ) ) + 1 ) );
else if( m_level <= 44 )
exp = ( expNeeded / ( 550 - levelDiff ) ) + cappedLevelDiff + ( cappedLevelDiff * ( ( rand() % ( cappedLevelDiff * 6 ) ) + 1 ) );
else if( m_level <= 50 )
exp = ( expNeeded / ( 750 - levelDiff ) ) + cappedLevelDiff + ( cappedLevelDiff * ( ( rand() % ( cappedLevelDiff * 5 ) ) + 1 ) );
else
exp = ( expNeeded / ( 1200 - levelDiff ) ) + cappedLevelDiff + ( cappedLevelDiff * ( ( rand() % ( cappedLevelDiff * 4 ) ) + 1 ) );
// todo: this is actually retarded, we need real rand()
srand( static_cast< uint32_t > ( time( nullptr ) ) );
auto pPlayer = pHateEntry->m_pActor->getAsPlayer();
pPlayer->gainExp( exp );
pPlayer->onMobKill( m_nameId );
}
}
}
hateListClear();
}
void Core::Entity::BattleNpc::onActionHostile( Actor& source )
{
if( hateListGetHighest() == nullptr )
aggro( source );
if( getClaimer() == nullptr )
setOwner( source.getAsPlayer() );
}
Core::Entity::ActorPtr Core::Entity::BattleNpc::getClaimer() const
{
return m_pOwner;
}
// HACK: this is highly experimental code, will have to be changed eventually
// since there are different types of mobs... (stationary, moving...) likely to be
// handled by scripts entirely.
void Core::Entity::BattleNpc::update( int64_t currTime )
{
if( !isAlive() )
{
m_status = ActorStatus::Idle;
m_mode = MODE_IDLE;
return;
}
updateStatusEffects();
float distance = Math::Util::distance( m_pos.x, m_pos.y, m_pos.z,
m_posOrigin.x, m_posOrigin.y, m_posOrigin.z );
if( ( distance > 70 ) && m_mode != MODE_RETREAT )
{
changeTarget( INVALID_GAME_OBJECT_ID );
m_mode = MODE_RETREAT;
hateListClear();
setOwner( nullptr );
}
switch( m_mode )
{
case MODE_RETREAT:
{
if( moveTo( m_posOrigin ) )
m_mode = MODE_IDLE;
}
break;
case MODE_IDLE:
{
ActorPtr pClosestActor = getClosestActor();
if( pClosestActor && pClosestActor->isAlive() )
{
distance = Math::Util::distance( getPos().x, getPos().y, getPos().z,
pClosestActor->getPos().x,
pClosestActor->getPos().y,
pClosestActor->getPos().z );
//if( distance < 8 && getbehavior() == 2 )
// aggro( pClosestActor );
}
}
break;
case MODE_COMBAT:
{
ActorPtr pClosestActor = hateListGetHighest();
if( pClosestActor != nullptr && !pClosestActor->isAlive() )
{
hateListRemove( *pClosestActor );
pClosestActor = hateListGetHighest();
}
if( pClosestActor != nullptr )
{
distance = Math::Util::distance( getPos().x, getPos().y, getPos().z,
pClosestActor->getPos().x,
pClosestActor->getPos().y,
pClosestActor->getPos().z );
if( distance > 4 )
moveTo( pClosestActor->getPos() );
else
{
if( face( pClosestActor->getPos() ) )
sendPositionUpdate();
// in combat range. ATTACK!
autoAttack( pClosestActor );
}
}
else
{
changeTarget( INVALID_GAME_OBJECT_ID );
setStance( Stance::Passive );
setOwner( nullptr );
m_mode = MODE_RETREAT;
}
}
break;
}
}
uint32_t Core::Entity::BattleNpc::getTimeOfDeath() const
{
return m_timeOfDeath;
}
void Core::Entity::BattleNpc::setTimeOfDeath( uint32_t tod )
{
m_timeOfDeath = tod;
}

View file

@ -1,115 +0,0 @@
#ifndef _BATTLENPC_H
#define _BATTLENPC_H
#include "Actor.h"
namespace Core {
namespace Entity {
enum StateMode
{
MODE_COMBAT,
MODE_RETREAT,
MODE_IDLE,
};
typedef struct
{
uint32_t m_hateAmount;
ActorPtr m_pActor;
} HateListEntry;
// class for Mobs inheriting from Actor
class BattleNpc : public Actor
{
public:
BattleNpc();
virtual ~BattleNpc() override;
BattleNpc( uint16_t modelId, uint16_t nameid, const Common::FFXIVARR_POSITION3& spawnPos, uint16_t bnpcBaseId = 0,
uint32_t type = 2, uint8_t level = 0, uint8_t behaviour = 1, uint32_t mobType = 0 );
//BattleNpc( uint32_t modelId,
// uint32_t nameId,
// uint32_t bnpcBaseId,
// uint32_t level,
// const Common::FFXIVARR_POSITION3& spawnPos,
// uint32_t type = 2, uint32_t behaviour = 1, uint32_t mobType = 0 );
void initStatusEffectContainer();
// send spawn packets to pTarget
void spawn( PlayerPtr pTarget ) override;
// send despawn packets to pTarget
void despawn( PlayerPtr pTarget ) override;
uint8_t getLevel() const override;
StateMode getMode() const;
void setMode( StateMode mode );
uint8_t getbehavior() const;
void hateListAdd( Actor& actor, int32_t hateAmount );
void hateListUpdate( Actor& actor, int32_t hateAmount );
void hateListRemove( Actor& actor );
bool hateListHasActor( Actor& actor );
void resetPos();
uint32_t getNameId() const;
void hateListClear();
ActorPtr hateListGetHighest();
void aggro( Actor& actor );
void deaggro( Actor& actor );
void setOwner( PlayerPtr pPlayer );
void onDeath() override;
void onActionHostile( Actor& source ) override;
ActorPtr getClaimer() const;
void sendPositionUpdate();
// return true if it reached the position
bool moveTo( Common::FFXIVARR_POSITION3& pos );
void update( int64_t currTime ) override;
uint32_t getTimeOfDeath() const;
void setTimeOfDeath( uint32_t tod );
private:
static uint32_t m_nextID;
StateMode m_mode;
Common::FFXIVARR_POSITION3 m_posOrigin;
uint8_t m_level;
uint16_t m_modelId;
uint16_t m_nameId;
uint16_t m_bnpcBaseId;
uint8_t m_behavior;
uint32_t m_unk1;
uint32_t m_unk2;
std::set< HateListEntry* > m_hateList;
ActorPtr m_pOwner;
uint32_t m_timeOfDeath;
uint32_t m_mobType;
};
}
}
#endif

View file

@ -1,37 +0,0 @@
#include "BattleNpcTemplate.h"
Core::Entity::BattleNpcTemplate::BattleNpcTemplate()
{
}
Core::Entity::BattleNpcTemplate::BattleNpcTemplate( std::string templateName, uint32_t bnpcBaseId,
uint32_t bnpcNameId, uint32_t modelId, std::string aiName ) :
m_templateName( templateName ),
m_bnpcBaseId( bnpcBaseId ),
m_bnpcNameId( bnpcNameId ),
m_modelId( modelId ),
m_aiName( aiName )
{
}
Core::Entity::BattleNpcTemplate::~BattleNpcTemplate()
{
}
uint32_t Core::Entity::BattleNpcTemplate::getBnpcBaseId() const
{
return m_bnpcBaseId;
}
uint32_t Core::Entity::BattleNpcTemplate::getBnpcNameId() const
{
return m_bnpcNameId;
}
uint32_t Core::Entity::BattleNpcTemplate::getModelId() const
{
return m_modelId;
}

View file

@ -1,38 +0,0 @@
#ifndef _BATTLENPCTEMPLATE_H
#define _BATTLENPCTEMPLATE_H
#include <stdint.h>
#include <string>
namespace Core {
namespace Entity {
/**
* \brief BattleNpcTemplate - Class which defines a template specific BNpcs can be created from
*/
class BattleNpcTemplate
{
public:
BattleNpcTemplate();
BattleNpcTemplate( std::string templateName, uint32_t bnpcBaseId, uint32_t bnpcNameId, uint32_t modelId, std::string aiName );
~BattleNpcTemplate();
uint32_t getBnpcBaseId() const;
uint32_t getBnpcNameId() const;
uint32_t getModelId() const;
private:
std::string m_templateName;
std::string m_aiName;
uint32_t m_bnpcBaseId = 0;
uint32_t m_bnpcNameId = 0;
uint32_t m_modelId = 0;
};
}
}
#endif

View file

@ -0,0 +1,763 @@
#include <common/Util/Util.h>
#include <common/Util/UtilMath.h>
#include <common/Network/PacketContainer.h>
#include <common/Exd/ExdDataGenerated.h>
#include <common/Network/GamePacket.h>
#include "Forwards.h"
#include "Action/Action.h"
#include "Zone/Zone.h"
#include "Network/GameConnection.h"
#include "Network/PacketWrappers/ActorControlPacket142.h"
#include "Network/PacketWrappers/ActorControlPacket143.h"
#include "Network/PacketWrappers/ActorControlPacket144.h"
#include "Network/PacketWrappers/UpdateHpMpTpPacket.h"
#include "StatusEffect/StatusEffect.h"
#include "Action/ActionCollision.h"
#include "ServerZone.h"
#include "Session.h"
#include "Math/CalcBattle.h"
#include "Chara.h"
#include "Player.h"
#include "Zone/TerritoryMgr.h"
#include "Framework.h"
extern Core::Framework g_framework;
using namespace Core::Common;
using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;
Core::Entity::Chara::Chara( ObjKind type ) :
Actor( type )
{
// initialize the free slot queue
for( uint8_t i = 0; i < MAX_STATUS_EFFECTS; i++ )
{
m_statusEffectFreeSlotQueue.push( i );
}
}
Core::Entity::Chara::~Chara()
{
}
/*! \return the actors name */
std::string Core::Entity::Chara::getName() const
{
return std::string( m_name );
}
/*! \return current stance of the actors */
Core::Entity::Chara::Stance Core::Entity::Chara::getStance() const
{
return m_currentStance;
}
/*! \return actor stats */
Core::Entity::Chara::ActorStats Core::Entity::Chara::getStats() const
{
return m_baseStats;
}
/*! \return current HP */
uint32_t Core::Entity::Chara::getHp() const
{
return m_hp;
}
/*! \return current MP */
uint32_t Core::Entity::Chara::getMp() const
{
return m_mp;
}
/*! \return current TP */
uint16_t Core::Entity::Chara::getTp() const
{
return m_tp;
}
/*! \return current GP */
uint16_t Core::Entity::Chara::getGp() const
{
return m_gp;
}
/*! \return current invincibility type */
InvincibilityType Core::Entity::Chara::getInvincibilityType() const
{
return m_invincibilityType;
}
/*! \return current class or job */
Core::Common::ClassJob Core::Entity::Chara::getClass() const
{
return m_class;
}
/*! \return current class or job as int32_t ( this feels pointless ) */
uint8_t Core::Entity::Chara::getClassAsInt() const
{
return static_cast< uint8_t >( m_class );
}
/*! \param ClassJob to set */
void Core::Entity::Chara::setClass( Common::ClassJob classJob )
{
m_class = classJob;
}
/*! \param Id of the target to set */
void Core::Entity::Chara::setTargetId( uint64_t targetId )
{
m_targetId = targetId;
}
/*! \return Id of the current target */
uint64_t Core::Entity::Chara::getTargetId() const
{
return m_targetId;
}
/*! \return True if the actor is alive */
bool Core::Entity::Chara::isAlive() const
{
return ( m_hp > 0 );
}
/*! \return max hp for the actor */
uint32_t Core::Entity::Chara::getMaxHp() const
{
return m_baseStats.max_hp;
}
/*! \return max mp for the actor */
uint32_t Core::Entity::Chara::getMaxMp() const
{
return m_baseStats.max_mp;
}
/*! \return reset hp to current max hp */
void Core::Entity::Chara::resetHp()
{
m_hp = getMaxHp();
sendStatusUpdate( true );
}
/*! \return reset mp to current max mp */
void Core::Entity::Chara::resetMp()
{
m_mp = getMaxMp();
sendStatusUpdate( true );
}
/*! \param hp amount to set ( caps to maxHp ) */
void Core::Entity::Chara::setHp( uint32_t hp )
{
m_hp = hp < getMaxHp() ? hp : getMaxHp();
sendStatusUpdate( true );
}
/*! \param mp amount to set ( caps to maxMp ) */
void Core::Entity::Chara::setMp( uint32_t mp )
{
m_mp = mp < getMaxMp() ? mp : getMaxMp();
sendStatusUpdate( true );
}
/*! \param gp amount to set*/
void Core::Entity::Chara::setGp( uint32_t gp )
{
m_gp = gp;
sendStatusUpdate( true );
}
/*! \param type invincibility type to set */
void Core::Entity::Chara::setInvincibilityType( Common::InvincibilityType type )
{
m_invincibilityType = type;
}
/*! \return current status of the actor */
Core::Entity::Chara::ActorStatus Core::Entity::Chara::getStatus() const
{
return m_status;
}
/*! \param status to set */
void Core::Entity::Chara::setStatus( ActorStatus status )
{
m_status = status;
}
/*!
Performs necessary steps to mark an actor dead.
Sets hp/mp/tp, sets status, plays animation and fires onDeath event
*/
void Core::Entity::Chara::die()
{
m_status = ActorStatus::Dead;
m_hp = 0;
m_mp = 0;
m_tp = 0;
// fire onDeath event
onDeath();
// if the actor is a player, the update needs to be send to himself too
bool selfNeedsUpdate = isPlayer();
sendToInRangeSet( ActorControlPacket142( m_id, SetStatus, static_cast< uint8_t >( ActorStatus::Dead ) ), selfNeedsUpdate );
// TODO: not all actor show the death animation when they die, some quest npcs might just despawn
// although that might be handled by setting the HP to 1 and doing some script magic
sendToInRangeSet( ActorControlPacket142( m_id, DeathAnimation, 0, 0, 0, 0x20 ), selfNeedsUpdate );
}
/*!
Calculates and sets the rotation to look towards a specified
position
\param Position to look towards
*/
bool Core::Entity::Chara::face( const Common::FFXIVARR_POSITION3& p )
{
float oldRot = getRot();
float rot = Math::Util::calcAngFrom( getPos().x, getPos().z, p.x, p.z );
float newRot = PI - rot + ( PI / 2 );
m_pCell = nullptr;
setRot( newRot );
return oldRot != newRot ? true : false;
}
/*!
Set and propagate the actor stance to in range players
( not the actor himself )
\param stance to set
*/
void Core::Entity::Chara::setStance( Stance stance )
{
m_currentStance = stance;
sendToInRangeSet( ActorControlPacket142( m_id, ToggleAggro, stance, 1 ) );
}
/*!
Check if an action is queued for execution, if so update it
and if fully performed, clean up again.
\return true if a queued action has been updated
*/
bool Core::Entity::Chara::checkAction()
{
if( m_pCurrentAction == nullptr )
return false;
if( m_pCurrentAction->update() )
m_pCurrentAction.reset();
return true;
}
/*!
Change the current target and propagate to in range players
\param target actor id
*/
void Core::Entity::Chara::changeTarget( uint64_t targetId )
{
setTargetId( targetId );
sendToInRangeSet( ActorControlPacket144( m_id, SetTarget, 0, 0, 0, 0, targetId ) );
}
/*!
Dummy function \return 0
*/
uint8_t Core::Entity::Chara::getLevel() const
{
return 0;
}
/*!
Let an actor take damage and perform necessary steps
according to resulting hp, propagates new hp value to players
in range
TODO: eventually this needs to distinguish between physical and
magical dmg and take status effects into account
\param amount of damage to be taken
*/
void Core::Entity::Chara::takeDamage( uint32_t damage )
{
if( damage >= m_hp )
{
switch( m_invincibilityType ) {
case InvincibilityNone:
setHp( 0 );
die();
break;
case InvincibilityRefill:
resetHp();
break;
case InvincibilityStayAlive:
setHp( 0 );
break;
}
}
else
m_hp -= damage;
sendStatusUpdate( false );
}
/*!
Let an actor get healed and perform necessary steps
according to resulting hp, propagates new hp value to players
in range
\param amount of hp to be healed
*/
void Core::Entity::Chara::heal( uint32_t amount )
{
if( ( m_hp + amount ) > getMaxHp() )
{
m_hp = getMaxHp();
}
else
m_hp += amount;
sendStatusUpdate( false );
}
/*!
Send an HpMpTp update to players in range ( and potentially to self )
TODO: poor naming, should be changed. Status is not HP. Also should be virtual
so players can have their own version and we can abolish the param.
\param true if the update should also be sent to the actor ( player ) himself
*/
void Core::Entity::Chara::sendStatusUpdate( bool toSelf )
{
UpdateHpMpTpPacket updateHpPacket( *this );
sendToInRangeSet( updateHpPacket );
}
/*! \return ActionPtr of the currently registered action, or nullptr */
Core::Action::ActionPtr Core::Entity::Chara::getCurrentAction() const
{
return m_pCurrentAction;
}
/*! \param ActionPtr of the action to be registered */
void Core::Entity::Chara::setCurrentAction( Core::Action::ActionPtr pAction )
{
m_pCurrentAction = pAction;
}
/*!
Autoattack prototype implementation
TODO: move the check if the autoAttack can be performed to the callee
also rename autoAttack to autoAttack as that is more elaborate
On top of that, this only solves attacks from melee classes.
Will have to be extended for ranged attacks.
\param ActorPtr the autoAttack is performed on
*/
void Core::Entity::Chara::autoAttack( CharaPtr pTarget )
{
uint64_t tick = Util::getTimeMs();
if( ( tick - m_lastAttack ) > 2500 )
{
pTarget->onActionHostile( *this );
m_lastAttack = tick;
srand( static_cast< uint32_t >( tick ) );
uint16_t damage = static_cast< uint16_t >( 10 + rand() % 12 );
uint32_t variation = static_cast< uint32_t >( 0 + rand() % 4 );
ZoneChannelPacket< FFXIVIpcEffect > effectPacket( getId() );
effectPacket.data().targetId = pTarget->getId();
effectPacket.data().actionAnimationId = 0x366;
effectPacket.data().unknown_2 = variation;
// effectPacket.data().unknown_3 = 1;
effectPacket.data().actionTextId = 0x366;
effectPacket.data().numEffects = 1;
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRot() );
effectPacket.data().effectTarget = pTarget->getId();
effectPacket.data().effects[0].value = damage;
effectPacket.data().effects[0].effectType = ActionEffectType::Damage;
effectPacket.data().effects[0].hitSeverity = static_cast< ActionHitSeverityType >( variation );
effectPacket.data().effects[0].unknown_3 = 7;
sendToInRangeSet( effectPacket );
if( isPlayer() )
getAsPlayer()->queuePacket( effectPacket );
pTarget->takeDamage( damage );
}
}
/*!
ChaiScript Skill Handler.
\param GamePacketPtr to send
\param bool should be send to self?
*/
void Core::Entity::Chara::handleScriptSkill( uint32_t type, uint16_t actionId, uint64_t param1,
uint64_t param2, Entity::Chara& target )
{
if( isPlayer() )
{
getAsPlayer()->sendDebug( std::to_string( target.getId() ) );
getAsPlayer()->sendDebug( "Handle script skill type: " + std::to_string( type ) );
}
auto actionInfoPtr = g_framework.getExdDataGen().get< Core::Data::Action >( actionId );
// Todo: Effect packet generator. 90% of this is basically setting params and it's basically unreadable.
// Prepare packet. This is seemingly common for all packets in the action handler.
ZoneChannelPacket< FFXIVIpcEffect > effectPacket( getId() );
effectPacket.data().targetId = target.getId();
effectPacket.data().actionAnimationId = actionId;
effectPacket.data().unknown_62 = 1; // Affects displaying action name next to number in floating text
effectPacket.data().unknown_2 = 1; // This seems to have an effect on the "double-cast finish" animation
effectPacket.data().actionTextId = actionId;
effectPacket.data().numEffects = 1;
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRot() );
effectPacket.data().effectTarget = target.getId();
// Todo: for each actor, calculate how much damage the calculated value should deal to them - 2-step damage calc. we only have 1-step
switch( type )
{
case ActionEffectType::Damage:
{
effectPacket.data().effects[0].value = static_cast< uint16_t >( param1 );
effectPacket.data().effects[0].effectType = ActionEffectType::Damage;
effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalDamage;
effectPacket.data().effects[0].unknown_3 = 7;
if( actionInfoPtr->castType == 1 && actionInfoPtr->effectRange != 0 || actionInfoPtr->castType != 1 )
{
// If action on this specific target is valid...
if ( isPlayer() && !ActionCollision::isActorApplicable( target, TargetFilter::Enemies ) )
break;
sendToInRangeSet( effectPacket, true );
if ( target.isAlive() )
target.onActionHostile( *this );
target.takeDamage( static_cast< uint32_t >( param1 ) );
}
else
{
auto actorsCollided = ActionCollision::getActorsHitFromAction( target.getPos(), getInRangeActors( true ),
actionInfoPtr, TargetFilter::Enemies );
for( const auto& pHitActor : actorsCollided )
{
effectPacket.data().targetId = pHitActor->getId();
effectPacket.data().effectTarget = pHitActor->getId();
// todo: send to range of what? ourselves? when mob script hits this is going to be lacking
sendToInRangeSet( effectPacket, true );
if( pHitActor->getAsChara()->isAlive() )
pHitActor->getAsChara()->onActionHostile( *this );
pHitActor->getAsChara()->takeDamage( static_cast< uint32_t >( param1 ) );
// Debug
if ( isPlayer() )
{
if ( pHitActor->isPlayer() )
getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) +
" (" + pHitActor->getAsChara()->getName() + ")" );
else
getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) );
}
}
}
break;
}
case ActionEffectType::Heal:
{
uint32_t calculatedHeal = Math::CalcBattle::calculateHealValue( getAsPlayer(), static_cast< uint32_t >( param1 ) );
effectPacket.data().effects[0].value = calculatedHeal;
effectPacket.data().effects[0].effectType = ActionEffectType::Heal;
effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalHeal;
if( actionInfoPtr->castType == 1 && actionInfoPtr->effectRange != 0 || actionInfoPtr->castType != 1 )
{
if( isPlayer() && !ActionCollision::isActorApplicable( target, TargetFilter::Allies ) )
break;
sendToInRangeSet( effectPacket, true );
target.heal( calculatedHeal );
}
else
{
// todo: get proper packets: the following was just kind of thrown together from what we know.
// atm buggy (packets look "delayed" from client)
auto actorsCollided = ActionCollision::getActorsHitFromAction( target.getPos(), getInRangeActors(true),
actionInfoPtr, TargetFilter::Allies );
for( auto pHitActor : actorsCollided )
{
effectPacket.data().targetId = target.getId();
effectPacket.data().effectTarget = pHitActor->getId();
sendToInRangeSet( effectPacket, true );
pHitActor->getAsChara()->heal( calculatedHeal );
// Debug
if( isPlayer() )
{
if( pHitActor->isPlayer() )
getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) +
" (" + pHitActor->getAsChara()->getName() + ")" );
else
getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) );
}
}
}
break;
}
default:
break;
}
}
/*! \param StatusEffectPtr to be applied to the actor */
void Core::Entity::Chara::addStatusEffect( StatusEffect::StatusEffectPtr pEffect )
{
int8_t nextSlot = getStatusEffectFreeSlot();
// if there is no slot left, do not add the effect
if( nextSlot == -1 )
return;
pEffect->applyStatus();
m_statusEffectMap[nextSlot] = pEffect;
ZoneChannelPacket< Server::FFXIVIpcAddStatusEffect > statusEffectAdd( getId() );
statusEffectAdd.data().actor_id = pEffect->getTargetActorId();
statusEffectAdd.data().actor_id1 = pEffect->getSrcActorId();
statusEffectAdd.data().current_hp = getHp();
statusEffectAdd.data().current_mp = getMp();
statusEffectAdd.data().current_tp = getTp();
statusEffectAdd.data().duration = static_cast< float >( pEffect->getDuration() ) / 1000;
statusEffectAdd.data().effect_id = pEffect->getId();
statusEffectAdd.data().effect_index = nextSlot;
statusEffectAdd.data().max_hp = getMaxHp();
statusEffectAdd.data().max_mp = getMaxMp();
statusEffectAdd.data().max_something = 1;
//statusEffectAdd.data().unknown2 = 28;
statusEffectAdd.data().param = pEffect->getParam();
sendToInRangeSet( statusEffectAdd, isPlayer() );
}
/*! \param StatusEffectPtr to be applied to the actor */
void Core::Entity::Chara::addStatusEffectById( uint32_t id, int32_t duration, Entity::Chara& source, uint16_t param )
{
auto effect = StatusEffect::make_StatusEffect( id, source.getAsChara(), getAsChara(), duration, 3000 );
effect->setParam( param );
addStatusEffect( effect );
}
/*! \param StatusEffectPtr to be applied to the actor */
void Core::Entity::Chara::addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Chara& source, uint16_t param )
{
if( hasStatusEffect( id ) )
return;
auto effect = StatusEffect::make_StatusEffect( id, source.getAsChara(), getAsChara(), duration, 3000 );
effect->setParam( param );
addStatusEffect( effect );
}
int8_t Core::Entity::Chara::getStatusEffectFreeSlot()
{
int8_t freeEffectSlot = -1;
if( m_statusEffectFreeSlotQueue.empty() )
return freeEffectSlot;
freeEffectSlot = m_statusEffectFreeSlotQueue.front();
m_statusEffectFreeSlotQueue.pop();
return freeEffectSlot;
}
void Core::Entity::Chara::statusEffectFreeSlot( uint8_t slotId )
{
m_statusEffectFreeSlotQueue.push( slotId );
}
void Core::Entity::Chara::removeSingleStatusEffectById( uint32_t id )
{
for( auto effectIt : m_statusEffectMap )
{
if( effectIt.second->getId() == id )
{
removeStatusEffect( effectIt.first );
break;
}
}
}
void Core::Entity::Chara::removeStatusEffect( uint8_t effectSlotId )
{
auto pEffectIt = m_statusEffectMap.find( effectSlotId );
if( pEffectIt == m_statusEffectMap.end() )
return;
statusEffectFreeSlot( effectSlotId );
auto pEffect = pEffectIt->second;
pEffect->removeStatus();
sendToInRangeSet( ActorControlPacket142( getId(), StatusEffectLose, pEffect->getId() ), isPlayer() );
m_statusEffectMap.erase( effectSlotId );
sendStatusEffectUpdate();
}
std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > Core::Entity::Chara::getStatusEffectMap() const
{
return m_statusEffectMap;
}
void Core::Entity::Chara::sendStatusEffectUpdate()
{
uint64_t currentTimeMs = Util::getTimeMs();
ZoneChannelPacket< Server::FFXIVIpcStatusEffectList > statusEffectList( getId() );
statusEffectList.data().classId = static_cast< uint8_t >( getClass() );
statusEffectList.data().level = getLevel();
statusEffectList.data().level1 = getLevel();
statusEffectList.data().current_hp = getHp();
statusEffectList.data().current_mp = getMp();
statusEffectList.data().currentTp = getTp();
statusEffectList.data().max_hp = getMaxHp();
statusEffectList.data().max_mp = getMaxMp();
uint8_t slot = 0;
for( auto effectIt : m_statusEffectMap )
{
float timeLeft = static_cast< float >( effectIt.second->getDuration() -
( currentTimeMs - effectIt.second->getStartTimeMs() ) ) / 1000;
statusEffectList.data().effect[slot].duration = timeLeft;
statusEffectList.data().effect[slot].effect_id = effectIt.second->getId();
statusEffectList.data().effect[slot].sourceActorId = effectIt.second->getSrcActorId();
slot++;
}
sendToInRangeSet( statusEffectList, isPlayer() );
}
void Core::Entity::Chara::updateStatusEffects()
{
uint64_t currentTimeMs = Util::getTimeMs();
uint32_t thisTickDmg = 0;
uint32_t thisTickHeal = 0;
for( auto effectIt : m_statusEffectMap )
{
uint8_t effectIndex = effectIt.first;
auto effect = effectIt.second;
uint64_t lastTick = effect->getLastTickMs();
uint64_t startTime = effect->getStartTimeMs();
uint32_t duration = effect->getDuration();
uint32_t tickRate = effect->getTickRate();
if( ( currentTimeMs - startTime ) > duration )
{
// remove status effect
removeStatusEffect( effectIndex );
// break because removing invalidates iterators
break;
}
if( ( currentTimeMs - lastTick ) > tickRate )
{
effect->setLastTick( currentTimeMs );
effect->onTick();
auto thisEffect = effect->getTickEffect();
switch( thisEffect.first )
{
case 1:
{
thisTickDmg += thisEffect.second;
break;
}
case 2:
{
thisTickHeal += thisEffect.second;
break;
}
}
}
}
if( thisTickDmg != 0 )
{
takeDamage( thisTickDmg );
sendToInRangeSet( ActorControlPacket142( getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Damage ), thisTickDmg ) );
}
if( thisTickHeal != 0 )
{
heal( thisTickDmg );
sendToInRangeSet( ActorControlPacket142( getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Heal ), thisTickHeal ) );
}
}
bool Core::Entity::Chara::hasStatusEffect( uint32_t id )
{
if( m_statusEffectMap.find( id ) != m_statusEffectMap.end() )
return true;
return false;
}
Chara::ModelType Chara::getModelType() const
{
return m_modelType;
}

View file

@ -0,0 +1,256 @@
#ifndef _ACTOR_H_
#define _ACTOR_H_
#include <common/Common.h>
#include <boost/enable_shared_from_this.hpp>
#include "Forwards.h"
#include "Actor.h"
#include <set>
#include <map>
#include <queue>
namespace Core {
namespace Entity {
/*!
\class Chara
\brief Base class for all animate actors
*/
class Chara : public Actor
{
public:
enum Stance : uint8_t
{
Passive = 0,
Active = 1,
};
enum DisplayFlags : uint16_t
{
ActiveStance = 0x001,
Invisible = 0x020,
HideHead = 0x040,
HideWeapon = 0x080,
Faded = 0x100,
Visor = 0x800,
};
enum struct ActorStatus : uint8_t
{
Idle = 0x01,
Dead = 0x02,
Sitting = 0x03,
Mounted = 0x04,
Crafting = 0x05,
Gathering = 0x06,
Melding = 0x07,
SMachine = 0x08
};
/*! ModelType as found in eventsystemdefine.exd */
enum ModelType : uint8_t
{
Human = 1,
DemiHuman = 2,
Monster = 3,
SharedGroup = 4,
Parts = 5
};
struct ActorStats
{
uint32_t max_mp = 0;
uint32_t max_hp = 0;
uint32_t str = 0;
uint32_t dex = 0;
uint32_t vit = 0;
uint32_t inte = 0;
uint32_t mnd = 0;
uint32_t pie = 0;
uint32_t tenacity = 0;
uint32_t attack = 0;
uint32_t defense = 0;
uint32_t accuracy = 0;
uint32_t spellSpeed = 0;
uint32_t magicDefense = 0;
uint32_t critHitRate = 0;
uint32_t resistSlash = 0;
uint32_t resistPierce = 0;
uint32_t resistBlunt = 0;
uint32_t attackPotMagic = 0;
uint32_t healingPotMagic = 0;
uint32_t determination = 0;
uint32_t skillSpeed = 0;
uint32_t resistSlow = 0;
uint32_t resistSilence = 0;
uint32_t resistBlind = 0;
uint32_t resistPoison = 0;
uint32_t resistStun = 0;
uint32_t resistSleep = 0;
uint32_t resistBind = 0;
uint32_t resistHeavy = 0;
uint32_t resistFire = 0;
uint32_t resistIce = 0;
uint32_t resistWind = 0;
uint32_t resistEarth = 0;
uint32_t resistLightning = 0;
uint32_t resistWater = 0;
} m_baseStats;
protected:
char m_name[34];
/*! Last tick time for the actor ( in ms ) */
uint64_t m_lastTickTime;
/*! Last time the actor performed an autoAttack ( in ms ) */
uint64_t m_lastAttack;
/*! Last time the actor was updated ( in ms ) */
uint64_t m_lastUpdate;
/*! Current stance of the actor */
Stance m_currentStance;
/*! Current staus of the actor */
ActorStatus m_status;
/*! Max HP of the actor ( based on job / class ) */
uint32_t m_maxHp;
/*! Max MP of the actor ( based on job / class ) */
uint32_t m_maxMp;
/*! Current HP of the actor */
uint32_t m_hp;
/*! Current MP of the actor */
uint32_t m_mp;
/*! Current TP of the actor */
uint16_t m_tp;
/*! Current GP of the actor */
uint16_t m_gp;
/*! Additional look info of the actor */
uint8_t m_customize[26];
/*! Current class of the actor */
Common::ClassJob m_class;
/*! Id of the currently selected target actor */
uint64_t m_targetId;
/*! Ptr to a queued action */
Action::ActionPtr m_pCurrentAction;
/*! Invincibility type */
Common::InvincibilityType m_invincibilityType;
/*! Type of model to use, humanoid for actors that use look data */
ModelType m_modelType;
/*! Status effects */
const uint8_t MAX_STATUS_EFFECTS = 30;
std::queue< uint8_t > m_statusEffectFreeSlotQueue;
std::vector< std::pair< uint8_t, uint32_t> > m_statusEffectList;
std::map< uint8_t, StatusEffect::StatusEffectPtr > m_statusEffectMap;
public:
Chara( ObjKind type );
virtual ~Chara() override;
virtual void calculateStats() {};
/// Status effect functions
void addStatusEffect( StatusEffect::StatusEffectPtr pEffect );
void removeStatusEffect( uint8_t effectSlotId );
void removeSingleStatusEffectById( uint32_t id );
void updateStatusEffects();
bool hasStatusEffect( uint32_t id );
int8_t getStatusEffectFreeSlot();
void statusEffectFreeSlot( uint8_t slotId );
std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > getStatusEffectMap() const;
void sendStatusEffectUpdate();
// 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 );
// remove a status effect by id
void removeSingleStatusEffectFromId( uint32_t id );
/// End Status Effect Functions
std::string getName() const;
bool face( const Common::FFXIVARR_POSITION3& p );
Stance getStance() const;
void setStance( Stance stance );
ActorStats getStats() const;
uint32_t getHp() const;
uint32_t getMp() const;
uint16_t getTp() const;
uint16_t getGp() const;
Common::InvincibilityType getInvincibilityType() const;
Common::ClassJob getClass() const;
ModelType getModelType() const;
uint8_t getClassAsInt() const;
void setClass( Common::ClassJob classJob );
void setTargetId( uint64_t targetId );
uint64_t getTargetId() const;
bool isAlive() const;
virtual uint32_t getMaxHp() const;
virtual uint32_t getMaxMp() const;
void resetHp();
void resetMp();
void setHp( uint32_t hp );
void setMp( uint32_t mp );
void setGp( uint32_t gp );
void setInvincibilityType( Common::InvincibilityType type );
void die();
ActorStatus getStatus() const;
void setStatus( ActorStatus status );
void handleScriptSkill( uint32_t type, uint16_t actionId, uint64_t param1, uint64_t param2, Entity::Chara& target );
virtual void autoAttack( CharaPtr pTarget );
virtual void onDeath() {};
virtual void onDamageTaken( Chara& pSource ) {};
virtual void onActionHostile( Chara& source ) {};
virtual void onActionFriendly( Chara& pSource ) {};
virtual void onTick() {};
virtual void changeTarget( uint64_t targetId );
virtual uint8_t getLevel() const;
virtual void sendStatusUpdate( bool toSelf = true );
virtual void takeDamage( uint32_t damage );
virtual void heal( uint32_t amount );
virtual bool checkAction();
virtual void update( int64_t currTime ) {};
Action::ActionPtr getCurrentAction() const;
void setCurrentAction( Action::ActionPtr pAction );
};
}
}
#endif

View file

@ -1,119 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
#include <cmath>
#include <common/Logging/Logger.h>
#include <common/Util/Util.h>
#include <common/Util/UtilMath.h>
#include "Network/PacketWrappers/MoveActorPacket.h"
#include "Network/PacketWrappers/ActorControlPacket142.h"
#include "Network/PacketWrappers/ActorControlPacket143.h"
#include "Player.h"
#include "EventNpc.h"
#include "Framework.h"
using namespace Core::Common;
using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;
extern Core::Framework g_framework;
uint32_t Core::Entity::EventNpc::m_nextID = 1249241694;
Core::Entity::EventNpc::EventNpc() :
Actor( ObjKind::EventNpc )
{
m_id = 0;
m_status = ActorStatus::Idle;
}
Core::Entity::EventNpc::~EventNpc()
{
}
Core::Entity::EventNpc::EventNpc( uint32_t enpcId, const Common::FFXIVARR_POSITION3& spawnPos, float rotation ) :
Actor( ObjKind::EventNpc )
{
EventNpc::m_nextID++;
m_id = EventNpc::m_nextID;
m_pos = spawnPos;
m_posOrigin = spawnPos;
m_targetId = static_cast< uint64_t >( INVALID_GAME_OBJECT_ID );
m_maxHp = 150;
m_maxMp = 100;
m_baseStats.max_hp = m_maxHp;
m_baseStats.max_mp = m_maxMp;
m_hp = m_maxHp;
m_mp = m_maxMp;
m_currentStance = Stance::Passive;
m_eNpcId = enpcId;
m_status = ActorStatus::Idle;
m_invincibilityType = InvincibilityType::InvincibilityNone;
m_rot = rotation;
}
// spawn this player for pTarget
/*! TODO: Retail additionally sends Look+Models for EventNpcs even though it is not needed,
add when the new exd reader is implemented(also counts for BNPCs) */
void Core::Entity::EventNpc::spawn( PlayerPtr pTarget )
{
ZoneChannelPacket< FFXIVIpcNpcSpawn > spawnPacket( getId(), pTarget->getId() );
spawnPacket.data().pos.x = m_pos.x;
spawnPacket.data().pos.y = m_pos.y;
spawnPacket.data().pos.z = m_pos.z;
spawnPacket.data().targetId = pTarget->getId();
spawnPacket.data().hPCurr = 1;
spawnPacket.data().hPMax = 1;
spawnPacket.data().bNPCBase = m_eNpcId;
spawnPacket.data().bNPCName = m_eNpcId;
spawnPacket.data().spawnIndex = pTarget->getSpawnIdForActorId( getId() );
spawnPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() );
spawnPacket.data().type = static_cast< uint8_t >( m_objKind );
pTarget->queuePacket( spawnPacket );
}
// despawn
void Core::Entity::EventNpc::despawn( PlayerPtr pTarget )
{
pTarget->freePlayerSpawnId( getId() );
ActorControlPacket143 controlPacket( m_id, DespawnZoneScreenMsg, 0x04, getId(), 0x01 );
pTarget->queuePacket( controlPacket );
}
uint8_t Core::Entity::EventNpc::getLevel() const
{
return m_level;
}
void Core::Entity::EventNpc::resetPos()
{
m_pos = m_posOrigin;
}
uint32_t Core::Entity::EventNpc::getEnpcId() const
{
return m_eNpcId;
}

View file

@ -1,42 +0,0 @@
#ifndef _EVENTNPC_H
#define _EVENTNPC_H
#include "Actor.h"
namespace Core {
namespace Entity {
// class for Mobs inheriting from Actor
class EventNpc : public Actor
{
public:
EventNpc();
virtual ~EventNpc() override;
EventNpc( uint32_t enpcId, const Common::FFXIVARR_POSITION3& spawnPos, float rotation );
// send spawn packets to pTarget
void spawn( PlayerPtr pTarget ) override;
// send despawn packets to pTarget
void despawn( PlayerPtr pTarget ) override;
uint8_t getLevel() const override;
void resetPos();
uint32_t getEnpcId() const;
private:
static uint32_t m_nextID;
Common::FFXIVARR_POSITION3 m_posOrigin;
uint8_t m_level;
uint32_t m_eNpcId;
};
}
}
#endif

View file

@ -0,0 +1,132 @@
#include "EventObject.h"
#include "Zone/InstanceContent.h"
#include "Actor/Player.h"
#include <common/Logging/Logger.h>
#include <common/Network/GamePacket.h>
#include <common/Network/GamePacketNew.h>
#include <common/Network/CommonNetwork.h>
#include <common/Network/PacketDef/Zone/ServerZoneDef.h>
#include <common/Network/PacketContainer.h>
#include <common/Util/UtilMath.h>
using namespace Core::Common;
using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;
extern Core::Logger g_log;
Core::Entity::EventObject::EventObject( uint32_t actorId, uint32_t objectId, uint32_t gimmickId,
uint8_t initialState, Common::FFXIVARR_POSITION3 pos,
float rotation, const std::string& givenName ) :
Core::Entity::Actor( ObjKind::EventObj ),
m_gimmickId( gimmickId ),
m_state( initialState ),
m_objectId( objectId ),
m_name( givenName )
{
m_id = actorId;
m_pos.x = pos.x;
m_pos.y = pos.y;
m_pos.z = pos.z;
m_rot = rotation;
}
uint32_t Core::Entity::EventObject::getGimmickId() const
{
return m_gimmickId;
}
uint32_t Core::Entity::EventObject::getObjectId() const
{
return m_objectId;
}
float Core::Entity::EventObject::getScale() const
{
return m_scale;
}
void Core::Entity::EventObject::setScale( float scale )
{
m_scale = scale;
}
Core::Entity::EventObject::OnTalkEventHandler Core::Entity::EventObject::getOnTalkHandler() const
{
return m_onTalkEventHandler;
}
void Core::Entity::EventObject::setOnTalkHandler( Core::Entity::EventObject::OnTalkEventHandler handler )
{
m_onTalkEventHandler = handler;
}
void Core::Entity::EventObject::setGimmickId( uint32_t gimmickId )
{
m_gimmickId = gimmickId;
}
uint8_t Core::Entity::EventObject::getState() const
{
return m_state;
}
void Core::Entity::EventObject::setState( uint8_t state )
{
m_state = state;
for( const auto& player : m_inRangePlayers )
{
ZoneChannelPacket< FFXIVIpcActorControl142 > eobjUpdatePacket( getId(), player->getId() );
eobjUpdatePacket.data().category = Common::ActorControlType::DirectorEObjMod;
eobjUpdatePacket.data().param1 = state;
player->queuePacket( eobjUpdatePacket );
}
}
void Core::Entity::EventObject::setParentInstance( Core::InstanceContentPtr instance )
{
m_parentInstance = instance;
}
Core::InstanceContentPtr Core::Entity::EventObject::getParentInstance() const
{
return m_parentInstance;
}
void Core::Entity::EventObject::spawn( Core::Entity::PlayerPtr pTarget )
{
auto spawnIndex = pTarget->getNextObjSpawnIndexForActorId( getId( ) );
if( !pTarget->isObjSpawnIndexValid( spawnIndex ) )
return;
g_log.debug( "Spawning EObj: id:" + std::to_string( getId() ) + " name:" + getName() );
ZoneChannelPacket< FFXIVIpcObjectSpawn > eobjStatePacket( getId(), pTarget->getId() );
eobjStatePacket.data().spawnIndex = spawnIndex;
eobjStatePacket.data().objKind = getObjKind();
eobjStatePacket.data().state = getState();
eobjStatePacket.data().objId = getObjectId();
eobjStatePacket.data().gimmickId = getGimmickId();
eobjStatePacket.data().position = getPos();
eobjStatePacket.data().scale = getScale();
eobjStatePacket.data().actorId = getId();
eobjStatePacket.data().rotation = Math::Util::floatToUInt16Rot( getRot() );
pTarget->queuePacket( eobjStatePacket );
}
void Core::Entity::EventObject::despawn( Core::Entity::PlayerPtr pTarget )
{
g_log.debug( "despawn eobj: " + std::to_string( getId() ) );
pTarget->freeObjSpawnIndexForActorId( getId( ) );
}
const std::string& Core::Entity::EventObject::getName() const
{
return m_name;
}

View file

@ -0,0 +1,52 @@
#ifndef SAPPHIRE_INSTANCEOBJECT_H
#define SAPPHIRE_INSTANCEOBJECT_H
#include "Actor.h"
namespace Core
{
namespace Entity
{
class EventObject : public Actor
{
public:
EventObject( uint32_t actorId, uint32_t objectId, uint32_t gimmickId, uint8_t initialState, Common::FFXIVARR_POSITION3 pos,
float rotation, const std::string& givenName = "none" );
using OnTalkEventHandler = std::function< void( Entity::Player&, Entity::EventObjectPtr, InstanceContentPtr, uint64_t ) >;
uint32_t getGimmickId() const;
void setGimmickId( uint32_t gimmickId );
uint8_t getState() const;
void setState( uint8_t state );
float getScale() const;
void setScale( float scale );
void setOnTalkHandler( OnTalkEventHandler handler );
OnTalkEventHandler getOnTalkHandler() const;
uint32_t getObjectId() const;
const std::string& getName() const;
InstanceContentPtr getParentInstance() const;
void setParentInstance( InstanceContentPtr instance );
void spawn( PlayerPtr pTarget ) override;
void despawn( PlayerPtr pTarget ) override;
protected:
uint32_t m_gimmickId;
uint32_t m_objectId;
uint8_t m_state;
float m_scale;
std::string m_name;
InstanceContentPtr m_parentInstance;
OnTalkEventHandler m_onTalkEventHandler;
};
}
}
#endif //SAPPHIRE_INSTANCEOBJECT_H

View file

@ -1,94 +0,0 @@
#include "GameObject.h"
#include "Player.h"
#include "Actor.h"
#include "BattleNpc.h"
#include "EventNpc.h"
Core::Entity::GameObject::GameObject( ObjKind type ) :
m_objKind( type )
{
}
uint32_t Core::Entity::GameObject::getId() const
{
return m_id;
}
Core::Entity::GameObject::ObjKind Core::Entity::GameObject::getObjKind() const
{
return m_objKind;
}
Core::Common::FFXIVARR_POSITION3& Core::Entity::GameObject::getPos()
{
return m_pos;
}
void Core::Entity::GameObject::setPos( float x, float y, float z )
{
m_pos.x = x;
m_pos.y = y;
m_pos.z = z;
}
void Core::Entity::GameObject::setPos( const Core::Common::FFXIVARR_POSITION3& pos )
{
m_pos = pos;
}
float Core::Entity::GameObject::getRot() const
{
return m_rot;
}
void Core::Entity::GameObject::setRot( float rot )
{
m_rot = rot;
}
bool Core::Entity::GameObject::isPlayer() const
{
return m_objKind == ObjKind::Player;
}
bool Core::Entity::GameObject::isBattleNpc() const
{
return m_objKind == ObjKind::BattleNpc;
}
bool Core::Entity::GameObject::isEventNpc() const
{
return m_objKind == ObjKind::EventNpc;
}
/*! \return pointer to this instance as ActorPtr */
Core::Entity::ActorPtr Core::Entity::GameObject::getAsActor()
{
return boost::dynamic_pointer_cast< Entity::Actor, Entity::GameObject >( shared_from_this() );
}
/*! \return pointer to this instance as PlayerPtr */
Core::Entity::PlayerPtr Core::Entity::GameObject::getAsPlayer()
{
if( !isPlayer() )
return nullptr;
return boost::dynamic_pointer_cast< Entity::Player, Entity::GameObject >( shared_from_this() );
}
/*! \return pointer to this instance as BattleNpcPtr */
Core::Entity::BattleNpcPtr Core::Entity::GameObject::getAsBattleNpc()
{
if( !isBattleNpc() )
return nullptr;
return boost::dynamic_pointer_cast< Entity::BattleNpc, Entity::GameObject >( shared_from_this() );
}
/*! \return pointer to this instance as EventNpcPtr */
Core::Entity::EventNpcPtr Core::Entity::GameObject::getAsEventNpc()
{
if( !isEventNpc() )
return nullptr;
return boost::dynamic_pointer_cast< Entity::EventNpc, Entity::GameObject >( shared_from_this() );
}

View file

@ -1,82 +0,0 @@
#ifndef _GAME_OBJECT_H_
#define _GAME_OBJECT_H_
#include <common/Common.h>
#include <boost/enable_shared_from_this.hpp>
#include "Forwards.h"
#include <set>
#include <map>
#include <queue>
namespace Core {
namespace Entity {
/*!
\class GameObject
\brief Base class for all actor/objects
*/
class GameObject : public boost::enable_shared_from_this< GameObject >
{
public:
enum ObjKind : uint8_t
{
None = 0x00,
Player = 0x01,
BattleNpc = 0x02,
EventNpc = 0x03,
Treasure = 0x04,
Aetheryte = 0x05,
GatheringPoint = 0x06,
EventObj = 0x07,
Mount = 0x08,
Companion = 0x09,
Retainer = 0x0A,
Area = 0x0B,
Housing = 0x0C,
Cutscene = 0x0D,
CardStand = 0x0E,
};
protected:
/*! Position of the object */
Common::FFXIVARR_POSITION3 m_pos;
/*! Rotation of the object */
float m_rot;
/*! Id of the actor */
uint32_t m_id;
/*! Type of the actor */
ObjKind m_objKind;
public:
explicit GameObject( ObjKind type );
virtual ~GameObject() {};
virtual void spawn( PlayerPtr pTarget ) {}
virtual void despawn( PlayerPtr pTarget ) {}
uint32_t getId() const;
ObjKind getObjKind() const;
Common::FFXIVARR_POSITION3& getPos();
void setPos( const Common::FFXIVARR_POSITION3& pos );
void setPos( float x, float y, float z );
float getRot() const;
void setRot( float rot );
bool isPlayer() const;
bool isBattleNpc() const;
bool isEventNpc() const;
ActorPtr getAsActor();
PlayerPtr getAsPlayer();
BattleNpcPtr getAsBattleNpc();
EventNpcPtr getAsEventNpc();
};
}
}
#endif

View file

@ -1,48 +0,0 @@
#include "InstanceObject.h"
#include "Zone/InstanceContent.h"
Core::Entity::InstanceObject::InstanceObject( uint32_t objectId, uint32_t mapLinkId ) :
Core::Entity::GameObject( ObjKind::EventObj ),
m_mapLinkId( mapLinkId ),
m_state( 0 )
{
m_id = objectId;
}
Core::Entity::InstanceObject::InstanceObject( uint32_t objectId, uint32_t mapLinkId, Common::FFXIVARR_POSITION3 pos ) :
InstanceObject( objectId, mapLinkId )
{
}
uint32_t Core::Entity::InstanceObject::getHierachyId() const
{
return m_mapLinkId;
}
void Core::Entity::InstanceObject::setHierachyId( uint32_t hierachyId )
{
m_mapLinkId = hierachyId;
}
uint8_t Core::Entity::InstanceObject::getState() const
{
return m_state;
}
void Core::Entity::InstanceObject::setState( uint8_t state )
{
m_state = state;
//m_parentInstance->updateInstanceObj( InstanceObjectPtr( this ) );
}
void Core::Entity::InstanceObject::setParentInstance( Core::InstanceContentPtr instance )
{
m_parentInstance = instance;
}
Core::InstanceContentPtr Core::Entity::InstanceObject::getParentInstance() const
{
return m_parentInstance;
}

View file

@ -1,33 +0,0 @@
#ifndef SAPPHIRE_INSTANCEOBJECT_H
#define SAPPHIRE_INSTANCEOBJECT_H
#include "GameObject.h"
namespace Core
{
namespace Entity
{
class InstanceObject : public GameObject
{
public:
InstanceObject( uint32_t objectId, uint32_t mapLinkId );
InstanceObject( uint32_t objectId, uint32_t mapLinkId, Common::FFXIVARR_POSITION3 pos );
uint32_t getHierachyId() const;
void setHierachyId( uint32_t hierachyId );
uint8_t getState() const;
void setState( uint8_t state );
InstanceContentPtr getParentInstance() const;
void setParentInstance( InstanceContentPtr instance );
protected:
uint32_t m_mapLinkId;
uint8_t m_state;
InstanceContentPtr m_parentInstance;
};
}
}
#endif //SAPPHIRE_INSTANCEOBJECT_H

View file

@ -11,7 +11,6 @@
#include "Session.h"
#include "Player.h"
#include "BattleNpc.h"
#include "Zone/TerritoryMgr.h"
#include "Zone/Zone.h"
@ -20,6 +19,7 @@
#include "Network/GameConnection.h"
#include "Network/PacketWrappers/ActorControlPacket142.h"
#include "Network/PacketWrappers/ActorControlPacket143.h"
#include "Network/PacketWrappers/ActorControlPacket144.h"
#include "Network/PacketWrappers/InitUIPacket.h"
#include "Network/PacketWrappers/ServerNoticePacket.h"
#include "Network/PacketWrappers/ChatPacket.h"
@ -40,6 +40,7 @@
#include "Event/EventHandler.h"
#include "Action/Action.h"
#include "Action/ActionTeleport.h"
#include "Action/EventAction.h"
#include "Action/EventItemAction.h"
@ -57,7 +58,7 @@ using namespace Core::Network::Packets::Server;
// player constructor
Core::Entity::Player::Player() :
Actor( ObjKind::Player ),
Chara( ObjKind::Player ),
m_lastWrite( 0 ),
m_lastPing( 0 ),
m_bIsLogin( false ),
@ -75,7 +76,8 @@ Core::Entity::Player::Player() :
m_bAutoattack( false ),
m_markedForRemoval( false ),
m_mount( 0 ),
m_directorInitialized( false )
m_directorInitialized( false ),
m_onEnterEventDone( false )
{
m_id = 0;
m_currentStance = Stance::Passive;
@ -83,6 +85,7 @@ Core::Entity::Player::Player() :
m_queuedZoneing = nullptr;
m_status = ActorStatus::Idle;
m_invincibilityType = InvincibilityType::InvincibilityNone;
m_modelType = ModelType::Human;
memset( m_questTracking, 0, sizeof( m_questTracking ) );
memset( m_name, 0, sizeof( m_name ) );
@ -90,12 +93,22 @@ Core::Entity::Player::Player() :
memset( m_searchMessage, 0, sizeof( m_searchMessage ) );
memset( m_classArray, 0, sizeof( m_classArray ) );
memset( m_expArray, 0, sizeof( m_expArray ) );
m_objSpawnIndexAllocator.init( MAX_DISPLAYED_EOBJS );
m_actorSpawnIndexAllocator.init( MAX_DISPLAYED_ACTORS, true );
}
Core::Entity::Player::~Player()
{
}
void Core::Entity::Player::injectPacket( std::string path )
{
auto session = g_framework.getServerZone().getSession( getId() );
if( session )
session->getZoneConnection()->injectPacket( path, *this );
}
// TODO: add a proper calculation based on race / job / level / gear
uint32_t Core::Entity::Player::getMaxHp()
{
@ -181,7 +194,7 @@ Core::Common::OnlineStatus Core::Entity::Player::getOnlineStatus()
if( m_onlineStatus & rpMask )
status = OnlineStatus::Roleplaying;
if( hasStateFlag( PlayerStateFlag::WatchingCutscene ) || hasStateFlag( PlayerStateFlag::WatchingCutscene1 ) )
if( hasStateFlag( PlayerStateFlag::WatchingCutscene ) )
status = OnlineStatus::ViewingCutscene;
// TODO: add all the logic for returning the proper online status, there probably is a better way for this alltogether
@ -307,8 +320,7 @@ void Core::Entity::Player::teleport( uint16_t aetheryteId, uint8_t type )
}
setStateFlag( PlayerStateFlag::BetweenAreas );
auto z_pos = g_framework.getTerritoryMgr().getTerritoryPosition( data->territory );
auto targetPos = g_framework.getTerritoryMgr().getTerritoryPosition( data->levelId );
Common::FFXIVARR_POSITION3 pos;
pos.x = 0;
@ -316,10 +328,10 @@ void Core::Entity::Player::teleport( uint16_t aetheryteId, uint8_t type )
pos.z = 0;
float rot = 0;
if( z_pos != nullptr )
if( targetPos != nullptr )
{
pos = z_pos->getTargetPosition();
rot = z_pos->getTargetRotation();
pos = targetPos->getTargetPosition();
rot = targetPos->getTargetRotation();
}
sendDebug( "Teleport: " + g_framework.getExdDataGen().get< Core::Data::PlaceName >( data->placeName )->name + " " +
@ -365,6 +377,7 @@ void Core::Entity::Player::returnToHomepoint()
void Core::Entity::Player::setZone( uint32_t zoneId )
{
m_onEnterEventDone = false;
if( !g_framework.getTerritoryMgr().movePlayer( zoneId, getAsPlayer() ) )
{
// todo: this will require proper handling, for now just return the player to their previous area
@ -381,6 +394,7 @@ void Core::Entity::Player::setZone( uint32_t zoneId )
bool Core::Entity::Player::setInstance( uint32_t instanceContentId )
{
m_onEnterEventDone = false;
auto instance = g_framework.getTerritoryMgr().getInstanceZonePtr( instanceContentId );
if( !instance )
return false;
@ -390,6 +404,7 @@ bool Core::Entity::Player::setInstance( uint32_t instanceContentId )
bool Core::Entity::Player::setInstance( ZonePtr instance )
{
m_onEnterEventDone = false;
if( !instance )
return false;
@ -440,43 +455,27 @@ uint8_t Core::Entity::Player::getGender() const
void Core::Entity::Player::initSpawnIdQueue()
{
while( !m_freeSpawnIdQueue.empty() )
{
m_freeSpawnIdQueue.pop();
}
for( int32_t i = 1; i < MAX_DISPLAYED_ACTORS; i++ )
{
m_freeSpawnIdQueue.push( i );
}
m_actorSpawnIndexAllocator.freeAllSpawnIndexes();
}
uint8_t Core::Entity::Player::getSpawnIdForActorId( uint32_t actorId )
{
if( m_freeSpawnIdQueue.empty() )
return 0;
uint8_t spawnId = m_freeSpawnIdQueue.front();
m_freeSpawnIdQueue.pop();
m_playerIdToSpawnIdMap[actorId] = spawnId;
return spawnId;
return m_actorSpawnIndexAllocator.getNextFreeSpawnIndex( actorId );
}
void Core::Entity::Player::assignSpawnIdToPlayerId( uint32_t actorId, uint8_t spawnId )
bool Core::Entity::Player::isActorSpawnIdValid( uint8_t spawnIndex )
{
m_playerIdToSpawnIdMap[actorId] = spawnId;
return m_actorSpawnIndexAllocator.isSpawnIndexValid( spawnIndex );
}
void Core::Entity::Player::registerAetheryte( uint8_t aetheryteId )
{
uint16_t index;
uint8_t value;
Util::valueToFlagByteIndexValue( aetheryteId, value, index );
m_aetheryte[index] |= value;
queuePacket( ActorControlPacket143( getId(), LearnTeleport, aetheryteId, 1 ) );
}
bool Core::Entity::Player::isAetheryteRegistered( uint8_t aetheryteId ) const
@ -639,7 +638,7 @@ void Core::Entity::Player::gainLevel()
ZoneChannelPacket< FFXIVIpcStatusEffectList > effectListPacket( getId() );
effectListPacket.data().classId = static_cast< uint8_t > ( getClass() );
effectListPacket.data().classId1 = static_cast< uint8_t > ( getClass() );
effectListPacket.data().level1 = getLevel();
effectListPacket.data().level = getLevel();
effectListPacket.data().current_hp = getMaxHp();
effectListPacket.data().current_mp = getMaxMp();
@ -654,23 +653,12 @@ void Core::Entity::Player::gainLevel()
ZoneChannelPacket< FFXIVIpcUpdateClassInfo > classInfoPacket( getId() );
classInfoPacket.data().classId = static_cast< uint8_t > ( getClass() );
classInfoPacket.data().classId1 = static_cast< uint8_t > ( getClass() );
classInfoPacket.data().level1 = getLevel();
classInfoPacket.data().level = getLevel();
classInfoPacket.data().nextLevelIndex = getLevel();
classInfoPacket.data().currentExp = getExp();
queuePacket( classInfoPacket );
}
void Core::Entity::Player::unlock()
{
queuePacket( PlayerStateFlagsPacket( *getAsPlayer(), PlayerStateFlagList{} ) );
}
void Core::Entity::Player::sendStatusUpdate( bool toSelf )
@ -831,6 +819,8 @@ void Core::Entity::Player::despawn( Entity::PlayerPtr pTarget )
{
auto pPlayer = pTarget;
g_framework.getLogger().debug( "despawning " + getName() + " for " + pTarget->getName() );
pPlayer->freePlayerSpawnId( getId() );
pPlayer->queuePacket( ActorControlPacket143( getId(), DespawnZoneScreenMsg, 0x04, getId(), 0x01 ) );
@ -989,7 +979,7 @@ void Core::Entity::Player::update( int64_t currTime )
setActorPosPacket.data().y = targetPos.y;
setActorPosPacket.data().z = targetPos.z;
sendToInRangeSet( setActorPosPacket, true );
setPosition( targetPos );
setPos( targetPos );
}
m_queuedZoneing.reset();
return;
@ -1007,14 +997,14 @@ void Core::Entity::Player::update( int64_t currTime )
if( !checkAction() )
{
if( m_targetId && m_currentStance == Entity::Actor::Stance::Active && isAutoattackOn() )
if( m_targetId && m_currentStance == Entity::Chara::Stance::Active && isAutoattackOn() )
{
auto mainWeap = m_pInventory->getItemAt( Inventory::GearSet0, Inventory::EquipSlot::MainHand );
// @TODO i dislike this, iterating over all in range actors when you already know the id of the actor you need...
for( auto actor : m_inRangeActors )
for( auto actor : m_inRangeActor )
{
if( actor->getId() == m_targetId && actor->isAlive() && mainWeap )
if( actor->getId() == m_targetId && actor->getAsChara()->isAlive() && mainWeap )
{
// default autoattack range
// TODO make this dependant on bnpc size
@ -1034,7 +1024,7 @@ void Core::Entity::Player::update( int64_t currTime )
if( ( currTime - m_lastAttack ) > mainWeap->getDelay() )
{
m_lastAttack = currTime;
autoAttack( actor );
autoAttack( actor->getAsChara() );
}
}
@ -1059,9 +1049,7 @@ void Core::Entity::Player::onMobKill( uint16_t nameId )
void Core::Entity::Player::freePlayerSpawnId( uint32_t actorId )
{
uint8_t spawnId = m_playerIdToSpawnIdMap[actorId];
m_playerIdToSpawnIdMap.erase( actorId );
m_freeSpawnIdQueue.push( spawnId );
auto spawnId = m_actorSpawnIndexAllocator.freeUsedSpawnIndex( actorId );
ZoneChannelPacket< FFXIVIpcActorFreeSpawn > freeActorSpawnPacket( getId() );
freeActorSpawnPacket.data().actorId = actorId;
@ -1206,7 +1194,7 @@ void Core::Entity::Player::performZoning( uint16_t zoneId, const Common::FFXIVAR
m_pos = pos;
m_zoneId = zoneId;
m_bMarkedForZoning = true;
setRotation( rotation );
setRot( rotation );
setZone( zoneId );
}
@ -1273,64 +1261,6 @@ void Core::Entity::Player::updateHowtosSeen( uint32_t howToId )
m_howTo[index] |= value;
}
void Core::Entity::Player::onMobAggro( BattleNpcPtr pBNpc )
{
hateListAdd( pBNpc );
queuePacket( ActorControlPacket142( getId(), ToggleAggro, 1 ) );
}
void Core::Entity::Player::onMobDeaggro( BattleNpcPtr pBNpc )
{
hateListRemove( pBNpc );
if( m_actorIdTohateSlotMap.empty() )
queuePacket( ActorControlPacket142( getId(), ToggleAggro ) );
}
void Core::Entity::Player::hateListAdd( BattleNpcPtr pBNpc )
{
if( m_freeHateSlotQueue.empty() )
return;
uint8_t hateId = m_freeHateSlotQueue.front();
m_freeHateSlotQueue.pop();
m_actorIdTohateSlotMap[pBNpc->getId()] = hateId;
sendHateList();
}
void Core::Entity::Player::hateListRemove( BattleNpcPtr pBNpc )
{
auto it = m_actorIdTohateSlotMap.begin();
for( ; it != m_actorIdTohateSlotMap.end(); ++it )
{
if( it->first == pBNpc->getId() )
{
uint8_t hateSlot = it->second;
m_freeHateSlotQueue.push( hateSlot );
m_actorIdTohateSlotMap.erase( it );
sendHateList();
return;
}
}
}
bool Core::Entity::Player::hateListHasMob( BattleNpcPtr pBNpc )
{
auto it = m_actorIdTohateSlotMap.begin();
for( ; it != m_actorIdTohateSlotMap.end(); ++it )
{
if( it->first == pBNpc->getId() )
return true;
}
return false;
}
void Core::Entity::Player::initHateSlotQueue()
{
m_freeHateSlotQueue = std::queue< uint8_t >();
@ -1366,6 +1296,11 @@ uint8_t* Core::Entity::Player::getTitleList()
return m_titleList;
}
const uint8_t* Core::Entity::Player::getTitleList() const
{
return m_titleList;
}
uint16_t Core::Entity::Player::getTitle() const
{
return m_activeTitle;
@ -1410,7 +1345,7 @@ uint8_t Core::Entity::Player::getEquipDisplayFlags() const
void Core::Entity::Player::mount( uint32_t id )
{
m_mount = id;
sendToInRangeSet( ActorControlPacket142( getId(), ActorControlType::SetStatus, static_cast< uint8_t >( Entity::Actor::ActorStatus::Mounted )), true );
sendToInRangeSet( ActorControlPacket142( getId(), ActorControlType::SetStatus, static_cast< uint8_t >( Entity::Chara::ActorStatus::Mounted )), true );
sendToInRangeSet( ActorControlPacket143( getId(), 0x39e, 12 ), true ); //?
ZoneChannelPacket< FFXIVIpcMount > mountPacket( getId() );
@ -1421,7 +1356,7 @@ void Core::Entity::Player::mount( uint32_t id )
void Core::Entity::Player::dismount()
{
sendToInRangeSet( ActorControlPacket142( getId(), ActorControlType::SetStatus,
static_cast< uint8_t >( Entity::Actor::ActorStatus::Idle )), true );
static_cast< uint8_t >( Entity::Chara::ActorStatus::Idle )), true );
sendToInRangeSet( ActorControlPacket143( getId(), ActorControlType::Dismount, 1 ), true );
m_mount = 0;
}
@ -1431,7 +1366,7 @@ uint8_t Core::Entity::Player::getCurrentMount() const
return m_mount;
}
void Core::Entity::Player::autoAttack( ActorPtr pTarget )
void Core::Entity::Player::autoAttack( CharaPtr pTarget )
{
auto mainWeap = m_pInventory->getItemAt( Inventory::GearSet0,
@ -1444,9 +1379,7 @@ void Core::Entity::Player::autoAttack( ActorPtr pTarget )
uint32_t damage = static_cast< uint32_t >( mainWeap->getAutoAttackDmg() );
uint32_t variation = 0 + rand() % 3;
if( getClass() == ClassJob::Machinist ||
getClass() == ClassJob::Bard ||
getClass() == ClassJob::Archer )
if( getClass() == ClassJob::Machinist || getClass() == ClassJob::Bard || getClass() == ClassJob::Archer )
{
ZoneChannelPacket< FFXIVIpcEffect > effectPacket( getId() );
effectPacket.data().targetId = pTarget->getId();
@ -1456,7 +1389,7 @@ void Core::Entity::Player::autoAttack( ActorPtr pTarget )
effectPacket.data().unknown_61 = 1;
effectPacket.data().unknown_62 = 1;
effectPacket.data().actionTextId = 8;
effectPacket.data().rotation = Math::Util::floatToUInt16Rot(getRotation());
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRot() );
effectPacket.data().effectTargetId = pTarget->getId();
effectPacket.data().effectTarget = pTarget->getId();
effectPacket.data().effects[0].value = damage;
@ -1477,7 +1410,7 @@ void Core::Entity::Player::autoAttack( ActorPtr pTarget )
effectPacket.data().unknown_61 = 1;
effectPacket.data().unknown_62 = 1;
effectPacket.data().actionTextId = 7;
effectPacket.data().rotation = Math::Util::floatToUInt16Rot(getRotation());
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRot() );
effectPacket.data().effectTarget = pTarget->getId();
effectPacket.data().effects[0].value = damage;
effectPacket.data().effects[0].effectType = Common::ActionEffectType::Damage;
@ -1550,18 +1483,20 @@ void Core::Entity::Player::setEorzeaTimeOffset( uint64_t timestamp )
queuePacket( packet );
}
void Player::setTerritoryId( uint32_t territoryId )
void Core::Entity::Player::setTerritoryId( uint32_t territoryId )
{
m_zoneId = territoryId;
}
uint32_t Player::getTerritoryId() const
uint32_t Core::Entity::Player::getTerritoryId() const
{
return m_zoneId;
}
void Player::sendZonePackets()
void Core::Entity::Player::sendZonePackets()
{
getCurrentZone()->onBeforePlayerZoneIn( *this );
ZoneChannelPacket< FFXIVIpcInit > initPacket( getId() );
initPacket.data().charId = getId();
queuePacket( initPacket );
@ -1627,17 +1562,135 @@ void Player::sendZonePackets()
if( getLastPing() == 0 )
sendQuestInfo();
getCurrentZone()->onEnterTerritory( *this );
getCurrentZone()->onPlayerZoneIn( *this );
m_bMarkedForZoning = false;
}
void Player::setDirectorInitialized( bool isInitialized )
void Core::Entity::Player::setDirectorInitialized( bool isInitialized )
{
m_directorInitialized = isInitialized;
}
bool Player::isDirectorInitialized() const
bool Core::Entity::Player::isDirectorInitialized() const
{
return m_directorInitialized;
}
void Core::Entity::Player::sendTitleList()
{
ZoneChannelPacket< FFXIVIpcPlayerTitleList > titleListPacket( getId() );
memcpy( titleListPacket.data().titleList, getTitleList(), sizeof( titleListPacket.data().titleList ) );
queuePacket( titleListPacket );
}
void Core::Entity::Player::finishZoning()
{
switch( getZoningType() )
{
case ZoneingType::None:
sendToInRangeSet( ActorControlPacket143( getId(), ZoneIn, 0x01 ), true );
break;
case ZoneingType::Teleport:
sendToInRangeSet( ActorControlPacket143( getId(), ZoneIn, 0x01, 0, 0, 110 ), true );
break;
case ZoneingType::Return:
case ZoneingType::ReturnDead:
{
if( getStatus() == Entity::Chara::ActorStatus::Dead )
{
resetHp();
resetMp();
setStatus( Entity::Chara::ActorStatus::Idle );
sendToInRangeSet( ActorControlPacket143( getId(), ZoneIn, 0x01, 0x01, 0, 111 ), true );
sendToInRangeSet( ActorControlPacket142( getId(), SetStatus,
static_cast< uint8_t >( Entity::Chara::ActorStatus::Idle ) ), true );
}
else
sendToInRangeSet( ActorControlPacket143( getId(), ZoneIn, 0x01, 0x00, 0, 111 ), true );
}
break;
case ZoneingType::FadeIn:
break;
}
setZoningType( Common::ZoneingType::None );
unsetStateFlag( PlayerStateFlag::BetweenAreas );
}
void Core::Entity::Player::emote( uint32_t emoteId, uint64_t targetId )
{
sendToInRangeSet( ActorControlPacket144( getId(), ActorControlType::Emote, emoteId, 0, 0, 0, targetId ) );
}
void Core::Entity::Player::teleportQuery( uint16_t aetheryteId )
{
// TODO: only register this action if enough gil is in possession
auto& exdDataGen = g_framework.getExdDataGen();
auto targetAetheryte = exdDataGen.get< Core::Data::Aetheryte >( aetheryteId );
if( targetAetheryte )
{
auto fromAetheryte = exdDataGen.get< Core::Data::Aetheryte >(
exdDataGen.get< Core::Data::TerritoryType >( getZoneId() )->aetheryte );
// calculate cost - does not apply for favorite points or homepoints neither checks for aether tickets
auto cost = static_cast< uint16_t > ( ( sqrt( pow( fromAetheryte->aetherstreamX - targetAetheryte->aetherstreamX, 2 ) +
pow( fromAetheryte->aetherstreamY - targetAetheryte->aetherstreamY, 2 ) ) / 2 ) + 100 );
// cap at 999 gil
cost = cost > uint16_t{999} ? uint16_t{999} : cost;
bool insufficientGil = getCurrency( Inventory::CurrencyType::Gil ) < cost;
// TODO: figure out what param1 really does
queuePacket( ActorControlPacket143( getId(), TeleportStart, insufficientGil ? 2 : 0, aetheryteId ) );
if( !insufficientGil )
{
Action::ActionPtr pActionTeleport;
pActionTeleport = Action::make_ActionTeleport( getAsPlayer(), aetheryteId, cost );
setCurrentAction( pActionTeleport );
}
}
}
uint8_t Core::Entity::Player::getNextObjSpawnIndexForActorId( uint32_t actorId )
{
return m_objSpawnIndexAllocator.getNextFreeSpawnIndex( actorId );
}
void Core::Entity::Player::resetObjSpawnIndex()
{
m_objSpawnIndexAllocator.freeAllSpawnIndexes();
}
void Core::Entity::Player::freeObjSpawnIndexForActorId( uint32_t actorId )
{
auto spawnId = m_objSpawnIndexAllocator.freeUsedSpawnIndex( actorId );
ZoneChannelPacket< FFXIVIpcObjectDespawn > freeObjectSpawnPacket( getId() );
freeObjectSpawnPacket.data().spawnIndex = spawnId;
queuePacket( freeObjectSpawnPacket );
}
bool Core::Entity::Player::isObjSpawnIndexValid( uint8_t index )
{
return m_objSpawnIndexAllocator.isSpawnIndexValid( index );
}
void Core::Entity::Player::setOnEnterEventDone( bool isDone )
{
m_onEnterEventDone = isDone;
}
bool Core::Entity::Player::isOnEnterEventDone() const
{
return m_onEnterEventDone;
}

View file

@ -8,8 +8,9 @@
#include <common/Network/PacketDef/Zone/ServerZoneDef.h>
#include <sapphire_zone/Social/FriendList.h>
#include <common/Common.h>
#include <common/Util/SpawnIndexAllocator.h>
#include "Actor.h"
#include "Chara.h"
#include "Inventory/Inventory.h"
#include "Event/EventHandler.h"
#include <map>
@ -37,7 +38,7 @@ struct QueuedZoning
* Inheriting from Actor
*
*/
class Player : public Actor
class Player : public Chara
{
public:
/*! Contructor */
@ -46,7 +47,9 @@ public:
/*! Destructor */
~Player();
void autoAttack( ActorPtr pTarget ) override;
void autoAttack( CharaPtr pTarget ) override;
void injectPacket( std::string path );
// EventHandlers
//////////////////////////////////////////////////////////////////////////////////////////////////////
@ -55,9 +58,12 @@ public:
/*! start an event item action */
void eventItemActionStart( uint32_t eventId, uint32_t action, ActionCallback finishCallback, ActionCallback interruptCallback, uint64_t additional );
/*! start/register a normal event */
void eventStart( uint64_t actorId, uint32_t eventId, Event::EventHandler::EventType eventParam, uint8_t eventParam1, uint32_t eventParam2 );
void eventStart( uint64_t actorId, uint32_t eventId, Event::EventHandler::EventType eventParam, uint8_t eventParam1, uint32_t eventParam2, uint32_t contentId = 0 );
/*! play a subevent */
void eventPlay( uint32_t eventId, uint32_t scene, uint32_t flags, uint32_t eventParam2, uint32_t eventParam3 );
void directorPlayScene( uint32_t eventId, uint32_t scene, uint32_t flags, uint32_t eventParam2, uint32_t eventParam3 );
/*! play a subevent */
void eventPlay( uint32_t eventId, uint32_t scene, uint32_t flags,
uint32_t eventParam2, uint32_t eventParam3, Event::EventHandler::SceneReturnCallback eventReturnCallback );
@ -347,16 +353,21 @@ public:
uint64_t getOnlineStatusMask() const;
/*! perform a teleport of a specified type ( teleport,return,aethernet ) */
void teleport( uint16_t aetheryteId, uint8_t type = 1 );
/*! query teleport of a specified type */
void teleportQuery( uint16_t aetheryteId );
/*! prepares zoning / fades out the screen */
void prepareZoning( uint16_t targetZone, bool fadeOut, uint8_t fadoutTime = 0, uint16_t animation = 0 );
/*! get player's title list (available titles) */
uint8_t* getTitleList();
const uint8_t* getTitleList() const;
/*! get player's active title */
uint16_t getTitle() const;
/*! add title to player title list */
void addTitle( uint16_t titleId );
/*! change player's active title */
void setTitle( uint16_t titleId );
/*! send the players title list */
void sendTitleList();
/*! change gear param state */
void setEquipDisplayFlags( uint8_t state );
/*! get gear param state */
@ -423,10 +434,10 @@ public:
void initSpawnIdQueue();
/*! get the spawn id mapped to a specific actorId */
uint8_t getSpawnIdForActorId( uint32_t actorId );
/*! assigns the given spawnId to the actor */
void assignSpawnIdToPlayerId( uint32_t actorId, uint8_t spawnId );
/*! frees the spawnId assigned to the given actor */
void freePlayerSpawnId( uint32_t actorId );
/*! checks if the given spawn id is valid */
bool isActorSpawnIdValid( uint8_t spawnId );
/*! send spawn packets to pTarget */
void spawn( PlayerPtr pTarget ) override;
/*! send despawn packets to pTarget */
@ -444,8 +455,6 @@ public:
bool hasStateFlag( Common::PlayerStateFlag flag ) const;
/* reset a specified flag */
void unsetStateFlag( Common::PlayerStateFlag flag );
/* helper function, send an empty state flag update */
void unlock();
// Player Session Handling
//////////////////////////////////////////////////////////////////////////////////////////////////////
@ -494,6 +503,10 @@ public:
/*! return true if the player is marked for zoning */
bool isMarkedForZoning() const;
void emote( uint32_t emoteId, uint64_t targetId );
void finishZoning();
void sendZonePackets();
Common::ZoneingType getZoningType() const;
@ -513,14 +526,7 @@ public:
// Player Battle Handling
//////////////////////////////////////////////////////////////////////////////////////////////////////
void onMobAggro( BattleNpcPtr pBNpc );
void onMobDeaggro( BattleNpcPtr pBNpc );
void initHateSlotQueue();
void hateListAdd( BattleNpcPtr pBNpc );
void hateListRemove( BattleNpcPtr pBNpc );
bool hateListHasMob( BattleNpcPtr pBNpc );
void sendHateList();
@ -566,6 +572,18 @@ public:
void setMarkedForRemoval();
bool isMarkedForRemoval() const;
void setOnEnterEventDone( bool isDone );
bool isOnEnterEventDone() const;
/*! gets the next available obj count */
uint8_t getNextObjSpawnIndexForActorId( uint32_t actorId );
/*! resets the players obj count */
void resetObjSpawnIndex();
/*! frees an obj count to be used by another eobj */
void freeObjSpawnIndexForActorId( uint32_t actorId );
/*! checks if a spawn index is valid */
bool isObjSpawnIndexValid( uint8_t index );
private:
uint32_t m_lastWrite;
uint32_t m_lastPing;
@ -580,6 +598,8 @@ private:
bool m_directorInitialized;
bool m_onEnterEventDone;
private:
Common::FFXIVARR_POSITION3 m_prevPos;
@ -636,8 +656,6 @@ private:
std::map< uint32_t, Event::EventHandlerPtr > m_eventHandlerMap;
std::map< uint32_t, uint8_t > m_playerIdToSpawnIdMap; // maps player to spawn id
std::queue< uint8_t > m_freeSpawnIdQueue; // queue with spawn ids free to be assigned
std::queue< uint8_t > m_freeHateSlotQueue; // queue with "hate slots" free to be assigned
std::map< uint32_t, uint8_t > m_actorIdTohateSlotMap;
@ -646,7 +664,7 @@ private:
boost::shared_ptr< Common::QuestActive > m_activeQuests[30];
int16_t m_questTracking[5];
uint8_t m_stateFlags[7];
uint8_t m_stateFlags[12];
uint8_t m_gmRank;
uint16_t zoneId;
@ -680,6 +698,9 @@ private:
uint32_t m_cfPenaltyUntil; // unix time
uint8_t m_mount;
Util::SpawnIndexAllocator< uint8_t > m_objSpawnIndexAllocator;
Util::SpawnIndexAllocator< uint8_t > m_actorSpawnIndexAllocator;
};
}

View file

@ -11,6 +11,7 @@
#include "Network/PacketWrappers/EventStartPacket.h"
#include "Network/PacketWrappers/EventPlayPacket.h"
#include "Network/PacketWrappers/EventFinishPacket.h"
#include "Network/PacketWrappers/DirectorPlayScenePacket.h"
#include "Action/EventAction.h"
#include "Action/EventItemAction.h"
@ -74,18 +75,39 @@ void Core::Entity::Player::checkEvent( uint32_t eventId )
}
void Core::Entity::Player::directorPlayScene( uint32_t eventId, uint32_t scene, uint32_t flags, uint32_t eventParam2,
uint32_t eventParam3 )
{
if( flags & 0x02 )
setStateFlag( PlayerStateFlag::WatchingCutscene );
auto pEvent = getEvent( eventId );
if( !pEvent )
{
g_framework.getLogger().error( "Could not find event " + std::to_string( eventId ) + ", event has not been started!" );
return;
}
pEvent->setPlayedScene( true );
pEvent->setEventReturnCallback( nullptr );
DirectorPlayScenePacket eventPlay( getId(), getId(), pEvent->getId(),
scene, flags, eventParam2, eventParam3 );
queuePacket( eventPlay );
}
void Core::Entity::Player::eventStart( uint64_t actorId, uint32_t eventId,
Event::EventHandler::EventType eventType, uint8_t eventParam1,
uint32_t eventParam2 )
uint32_t eventParam2, uint32_t contentId )
{
auto newEvent = Event::make_EventHandler( this, actorId, eventId, eventType, eventParam2 );
addEvent( newEvent );
setStateFlag( PlayerStateFlag::Occupied2 );
setStateFlag( PlayerStateFlag::InNpcEvent );
EventStartPacket eventStart( getId(), actorId, eventId, eventType, eventParam1, eventParam2 );
EventStartPacket eventStart( getId(), actorId, eventId, eventType, eventParam1, eventParam2, contentId );
queuePacket( eventStart );
@ -217,7 +239,7 @@ void Core::Entity::Player::eventFinish( uint32_t eventId, uint32_t freePlayer )
removeEvent( pEvent->getId() );
if( freePlayer == 1 )
unsetStateFlag( PlayerStateFlag::Occupied2 );
unsetStateFlag( PlayerStateFlag::InNpcEvent );
}
void Core::Entity::Player::eventActionStart( uint32_t eventId,
@ -226,7 +248,7 @@ void Core::Entity::Player::eventActionStart( uint32_t eventId,
ActionCallback interruptCallback,
uint64_t additional )
{
auto pEventAction = Action::make_EventAction( getAsActor(), eventId, action,
auto pEventAction = Action::make_EventAction( getAsChara(), eventId, action,
finishCallback, interruptCallback, additional );
setCurrentAction( pEventAction );
@ -256,7 +278,7 @@ void Core::Entity::Player::eventItemActionStart( uint32_t eventId,
ActionCallback interruptCallback,
uint64_t additional )
{
Action::ActionPtr pEventItemAction = Action::make_EventItemAction( getAsActor(), eventId, action,
Action::ActionPtr pEventItemAction = Action::make_EventItemAction( getAsChara(), eventId, action,
finishCallback, interruptCallback, additional );
setCurrentAction( pEventItemAction );
@ -289,7 +311,6 @@ void Core::Entity::Player::onDeath()
}
// TODO: slightly ugly here and way too static. Needs too be done properly
void Core::Entity::Player::onTick()
{

View file

@ -58,7 +58,7 @@ bool Core::Entity::Player::load( uint32_t charId, SessionPtr pSession )
m_pos.x = res->getFloat( "PosX" );
m_pos.y = res->getFloat( "PosY" );
m_pos.z = res->getFloat( "PosZ" );
setRotation( res->getFloat( "PosR" ) );
setRot( res->getFloat( "PosR" ) );
m_prevPos.x = res->getFloat( "OPosX" );
m_prevPos.y = res->getFloat( "OPosY" );
@ -79,7 +79,7 @@ bool Core::Entity::Player::load( uint32_t charId, SessionPtr pSession )
m_pos.x = m_prevPos.x;
m_pos.y = m_prevPos.y;
m_pos.z = m_prevPos.z;
setRotation( m_prevRot );
setRot( m_prevRot );
pCurrZone = g_framework.getTerritoryMgr().getZoneByTerriId( zoneId );
}
}
@ -104,7 +104,7 @@ bool Core::Entity::Player::load( uint32_t charId, SessionPtr pSession )
m_pos.x = 0.0f;
m_pos.y = 0.0f;
m_pos.z = 0.0f;
setRotation( 0.0f );
setRot( 0.0f );
}
// Stats
@ -230,9 +230,6 @@ bool Core::Entity::Player::load( uint32_t charId, SessionPtr pSession )
initSpawnIdQueue();
if( !m_playerIdToSpawnIdMap.empty() )
m_playerIdToSpawnIdMap.clear();
if( !g_framework.getTerritoryMgr().movePlayer( pCurrZone, getAsPlayer() ) )
return false;
@ -307,7 +304,10 @@ bool Core::Entity::Player::loadSearchInfo()
m_searchSelectClass = res->getUInt8( 1 );
m_searchSelectRegion = res->getUInt8( 2 );
sprintf( m_searchMessage, res->getString( 3 ).c_str() );
// todo: internally use an std::string instead of a char[]
auto searchMessage = res->getString( 3 );
std::copy( searchMessage.begin(), searchMessage.end(), m_searchMessage );
return true;
}
@ -360,7 +360,7 @@ void Core::Entity::Player::updateSql()
stmt->setDouble( 20, m_pos.x );
stmt->setDouble( 21, m_pos.y );
stmt->setDouble( 22, m_pos.z );
stmt->setDouble( 23, getRotation() );
stmt->setDouble( 23, getRot() );
stmt->setInt( 24, m_prevZoneType ); // OTerritoryType
stmt->setInt( 25, m_prevZoneId ); // OTerritoryId

View file

@ -70,3 +70,4 @@ else()
endif()
target_link_libraries( sapphire_zone ${Boost_LIBRARIES} )
cotire( sapphire_zone )

View file

@ -3,7 +3,6 @@
#include <common/Common.h>
#include "Actor/Player.h"
#include "Forwards.h"
namespace Core {

View file

@ -27,8 +27,7 @@
#include "Script/NativeScriptMgr.h"
#include "Actor/Player.h"
#include "Actor/BattleNpc.h"
#include "Actor/EventNpc.h"
#include "Actor/EventObject.h"
#include "Zone/Zone.h"
#include "Zone/InstanceContent.h"
@ -54,7 +53,6 @@ Core::DebugCommandHandler::DebugCommandHandler()
registerCommand( "replay", &DebugCommandHandler::replay, "Replays a saved capture folder.", 1 );
registerCommand( "nudge", &DebugCommandHandler::nudge, "Nudges you forward/up/down.", 1 );
registerCommand( "info", &DebugCommandHandler::serverInfo, "Show server info.", 0 );
registerCommand( "unlock", &DebugCommandHandler::unlockCharacter, "Unlock character.", 1 );
registerCommand( "help", &DebugCommandHandler::help, "Shows registered commands.", 0 );
registerCommand( "script", &DebugCommandHandler::script, "Server script utilities.", 1 );
registerCommand( "instance", &DebugCommandHandler::instance, "Instance utilities", 1 );
@ -173,11 +171,11 @@ void Core::DebugCommandHandler::set( char * data, Entity::Player& player, boost:
}
if( subCommand == "pos" )
player.setPosition( static_cast< float >( posX ),
player.setPos( static_cast< float >( posX ),
static_cast< float >( posY ),
static_cast< float >( posZ ) );
else
player.setPosition( player.getPos().x + static_cast< float >( posX ),
player.setPos( player.getPos().x + static_cast< float >( posX ),
player.getPos().y + static_cast< float >( posY ),
player.getPos().z + static_cast< float >( posZ ) );
@ -302,6 +300,14 @@ void Core::DebugCommandHandler::set( char * data, Entity::Player& player, boost:
player.sendDebug( "MSQ Guide updated " );
}
else if( subCommand == "weatheroverride" || subCommand == "wo" )
{
uint32_t weatherId;
sscanf( params.c_str(), "%d", &weatherId );
player.getCurrentZone()->setWeatherOverride( static_cast< Common::Weather >( weatherId ) );
}
else
{
player.sendUrgent( subCommand + " is not a valid SET command." );
@ -354,43 +360,6 @@ void Core::DebugCommandHandler::add( char * data, Entity::Player& player, boost:
player.addTitle( titleId );
player.sendNotice( "Added title (ID: " + std::to_string( titleId ) + ")" );
}
else if( subCommand == "spawn" )
{
int32_t model, name;
sscanf( params.c_str(), "%d %d", &model, &name );
auto pBNpc = Entity::make_BattleNpc( model, name, player.getPos() );
auto pZone = player.getCurrentZone();
pBNpc->setCurrentZone( pZone );
pZone->pushActor( pBNpc );
}
else if( subCommand == "sspawn" )
{
int32_t model, name, count, distCoefficient, i;
sscanf( params.c_str(), "%d %d %d %d", &model, &name, &count, &distCoefficient );
for ( i = 0; i < count; i++ )
{
Common::FFXIVARR_POSITION3 posC = player.getPos();
std::mt19937 gen( rand() * 1000 );
std::uniform_int_distribution< int > dis( distCoefficient * -1, distCoefficient );
posC.x += dis( gen );
posC.z += dis( gen );
Entity::BattleNpcPtr pBNpc( new Entity::BattleNpc( model, name, posC ) );
auto pZone = player.getCurrentZone();
pBNpc->setCurrentZone( pZone );
pZone->pushActor( pBNpc );
}
}
else if( subCommand == "op" )
{
// temporary research packet
@ -399,33 +368,6 @@ void Core::DebugCommandHandler::add( char * data, Entity::Player& player, boost:
auto pPe = Network::Packets::make_GamePacket( opcode, 0x30, player.getId(), player.getId() );
player.queuePacket( pPe );
}
else if( subCommand == "eventnpc-self" )
{
int32_t id;
sscanf( params.c_str(), "%d", &id );
Network::Packets::ZoneChannelPacket< Network::Packets::Server::FFXIVIpcNpcSpawn > spawnPacket( player.getId() );
spawnPacket.data().type = 3;
spawnPacket.data().pos = player.getPos();
spawnPacket.data().rotation = player.getRotation();
spawnPacket.data().bNPCBase = id;
spawnPacket.data().bNPCName = id;
spawnPacket.data().targetId = player.getId();
player.queuePacket( spawnPacket );
}
else if( subCommand == "eventnpc" )
{
int32_t id;
sscanf( params.c_str(), "%d", &id );
auto pENpc = Entity::make_EventNpc( id, player.getPos(), player.getRotation() );
auto pZone = player.getCurrentZone();
pENpc->setCurrentZone( pZone );
pZone->pushActor( pENpc );
}
else if( subCommand == "actrl" )
{
@ -507,7 +449,7 @@ void Core::DebugCommandHandler::get( char * data, Entity::Player& player, boost:
std::to_string( player.getPos().x ) + "\n" +
std::to_string( player.getPos().y ) + "\n" +
std::to_string( player.getPos().z ) + "\n" +
std::to_string( player.getRotation() ) + "\nMapId: " +
std::to_string( player.getRot() ) + "\nMapId: " +
std::to_string( map_id ) + "\nZoneID: " +
std::to_string(player.getCurrentZone()->getTerritoryId() ) + "\n" );
}
@ -612,7 +554,7 @@ void Core::DebugCommandHandler::nudge( char * data, Entity::Player& player, boos
}
else
{
float angle = player.getRotation() + ( PI / 2 );
float angle = player.getRot() + ( PI / 2 );
pos.x -= offset * cos( angle );
pos.z += offset * sin( angle );
player.sendNotice( "nudge: Placing forward " + std::to_string( offset ) + " yalms" );
@ -624,23 +566,18 @@ void Core::DebugCommandHandler::nudge( char * data, Entity::Player& player, boos
setActorPosPacket.data().x = player.getPos().x;
setActorPosPacket.data().y = player.getPos().y;
setActorPosPacket.data().z = player.getPos().z;
setActorPosPacket.data().r16 = Math::Util::floatToUInt16Rot( player.getRotation() );
setActorPosPacket.data().r16 = Math::Util::floatToUInt16Rot( player.getRot() );
player.queuePacket( setActorPosPacket );
}
}
void Core::DebugCommandHandler::serverInfo( char * data, Entity::Player& player, boost::shared_ptr< DebugCommand > command )
{
player.sendDebug( "SapphireServer " + Version::VERSION + "\nRev: " + Version::GIT_HASH );
player.sendDebug( "SapphireZone " + Version::VERSION + "\nRev: " + Version::GIT_HASH );
player.sendDebug( "Compiled: " __DATE__ " " __TIME__ );
player.sendDebug( "Sessions: " + std::to_string( g_framework.getServerZone().getSessionCount() ) );
}
void Core::DebugCommandHandler::unlockCharacter( char* data, Entity::Player& player, boost::shared_ptr< DebugCommand > command )
{
player.unlock();
}
void Core::DebugCommandHandler::script( char* data, Entity::Player &player, boost::shared_ptr< DebugCommand > command )
{
std::string subCommand;
@ -776,51 +713,58 @@ void Core::DebugCommandHandler::instance( char* data, Entity::Player &player, bo
}
else if( subCommand == "set" )
{
uint32_t instanceId;
uint32_t index;
uint32_t value;
sscanf( params.c_str(), "%d %d %d", &instanceId, &index, &value );
sscanf( params.c_str(), "%d %d", &index, &value );
auto pInstance = g_framework.getTerritoryMgr().getInstanceZonePtr( instanceId );
if( !pInstance )
auto instance = boost::dynamic_pointer_cast< InstanceContent >( player.getCurrentZone() );
if( !instance )
return;
auto instance = boost::dynamic_pointer_cast< InstanceContent >( pInstance );
instance->setVar( static_cast< uint8_t >( index ), static_cast< uint8_t >( value ) );
}
else if( subCommand == "objupdate" )
{
uint32_t objId;
sscanf( params.c_str(), "%d", &objId );
auto instance = boost::dynamic_pointer_cast< InstanceContent >( player.getCurrentZone() );
if( !instance )
return;
auto obj = instance->getInstanceObject( objId );
if( !obj )
return;
instance->updateInstanceObj( obj );
}
else if( subCommand == "objstate" )
{
uint32_t objId;
char objName[128];
uint8_t state;
sscanf( params.c_str(), "%d %hhu", &objId, &state );
sscanf( params.c_str(), "%s %hhu", objName, &state );
auto instance = boost::dynamic_pointer_cast< InstanceContent >( player.getCurrentZone() );
if( !instance )
return;
auto obj = instance->getInstanceObject( objId );
auto obj = instance->getEObjByName( objName );
if( !obj )
return;
obj->setState( state );
}
else if( subCommand == "seq" )
{
uint8_t seq;
sscanf( params.c_str(), "%hhu", &seq );
auto instance = boost::dynamic_pointer_cast< InstanceContent >( player.getCurrentZone() );
if( !instance )
return;
instance->setSequence( seq );
}
else if( subCommand == "branch" )
{
uint8_t branch;
sscanf( params.c_str(), "%hhu", &branch );
auto instance = boost::dynamic_pointer_cast< InstanceContent >( player.getCurrentZone() );
if( !instance )
return;
instance->setBranch( branch );
}
else if( subCommand == "festival" )
{
uint32_t festivalId;

View file

@ -168,3 +168,13 @@ void Core::Event::Director::setDirectorUI8JH( uint8_t value )
{
m_unionData.ui8lh.UI8JH = value;
}
void Core::Event::Director::setDirectorBranch( uint8_t value )
{
m_branch = value;
}
void Core::Event::Director::setDirectorSequence( uint8_t value )
{
m_sequence = value;
}

View file

@ -72,6 +72,9 @@ public:
void setDirectorUI8JL( uint8_t value );
void setDirectorUI8JH( uint8_t value );
void setDirectorSequence( uint8_t value );
void setDirectorBranch( uint8_t value );
private:
/*! Id of the content of the director */
uint16_t m_contentId;

View file

@ -61,6 +61,7 @@ namespace Core {
SpecialShop = 0x001B,
BahamutGuide = 0x001C,
FcTalk = 0x001F,
ICDirector = 0x8003,
};
using SceneReturnCallback = std::function< void( Entity::Player&, uint32_t, uint16_t, uint16_t, uint16_t ) > ;

View file

@ -1,13 +1,14 @@
#include <common/Common.h>
#include <common/Exd/ExdDataGenerated.h>
#include "Framework.h"
#include "EventHelper.h"
#include "EventHandler.h"
#include <boost/range/algorithm/remove_if.hpp>
#include <boost/algorithm/string/classification.hpp>
extern Core::Framework g_framework;
using namespace Core::Common;
std::string Core::Event::getEventName( uint32_t eventId )
@ -54,6 +55,15 @@ std::string Core::Event::getEventName( uint32_t eventId )
return "Aetheryte";
return "Aethernet";
}
case Event::EventHandler::EventHandlerType::ICDirector:
{
auto contentInfo = g_framework.getExdDataGen().get< Core::Data::InstanceContent >( eventId & 0xFFFF );
std::string name = contentInfo->name;
name.erase( boost::remove_if( name, boost::is_any_of( "★_ '()[]-\x1a\x1\x2\x1f\x1\x3.:" ) ), name.end() );
name[0] = toupper( name[0] );
return name;
}
case Event::EventHandler::EventHandlerType::Warp:
{

View file

@ -34,13 +34,10 @@ namespace Core
namespace Entity
{
TYPE_FORWARD( GameObject );
TYPE_FORWARD( Actor );
TYPE_FORWARD( Chara );
TYPE_FORWARD( Player );
TYPE_FORWARD( BattleNpc );
TYPE_FORWARD( EventNpc );
TYPE_FORWARD( BattleNpcTemplate );
TYPE_FORWARD( InstanceObject );
TYPE_FORWARD( EventObject );
}
namespace Event

View file

@ -720,7 +720,7 @@ bool Core::Inventory::load()
while( bagRes->next() )
{
uint16_t storageId = bagRes->getUInt16( 1 );
for( uint32_t i = 1; i <= 25; i++ )
for( uint32_t i = 1; i <= 35; i++ )
{
uint64_t uItemId = bagRes->getUInt64( i + 1 );
if( uItemId == 0 )
@ -890,7 +890,7 @@ uint8_t Core::Inventory::getFreeSlotsInBags()
uint8_t slots = 0;
for( uint8_t container : { 0, 1, 2, 3 } )
{
slots += 25 - m_inventoryMap[container]->getEntryCount();
slots += 34 - m_inventoryMap[container]->getEntryCount();
}
return slots;
}

View file

@ -13,7 +13,7 @@ extern Core::Framework g_framework;
Core::ItemContainer::ItemContainer( uint16_t locationId ) :
m_id( locationId ),
m_size( 25 )
m_size( 35 )
{
}

View file

@ -3,7 +3,8 @@
#include <common/Exd/ExdDataGenerated.h>
#include <common/Common.h>
#include "Actor/Actor.h"
#include "Actor/Chara.h"
#include "Actor/Player.h"
#include "CalcBattle.h"

View file

@ -2,7 +2,7 @@
#define _CALCBATTLE_H
#include <common/Common.h>
#include "Actor/Actor.h"
#include "Forwards.h"
using namespace Core::Entity;

View file

@ -3,7 +3,8 @@
#include <common/Exd/ExdDataGenerated.h>
#include <common/Common.h>
#include "Actor/Actor.h"
#include "Actor/Chara.h"
#include "Actor/Player.h"
#include "CalcStats.h"

View file

@ -2,7 +2,7 @@
#define _CALCSTATS_H
#include <common/Common.h>
#include "Actor/Actor.h"
#include "Forwards.h"
using namespace Core::Entity;

View file

@ -45,6 +45,65 @@ using namespace Core::Common;
using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;
enum ClientTrigger
{
ToggleSeathe = 0x01,
ToggleAutoAttack = 0x02,
ChangeTarget = 0x03,
Dismount = 0x65,
RemoveStatusEffect = 0x68,
CastCancel = 0x69,
Return = 0xC8, // return dead / accept raise
FinishZoning = 0xC9,
Teleport = 0xCA,
MarkPlayer = 0x12D, // Mark player, visible to party only
SetTitle = 0x12E,
TitleList = 0x12F,
UpdatedSeenHowTos = 0x133,
AllotAttribute = 0x135,
ClearWaymarks = 0x13A,
HuntingLogDetails = 0x194,
Timers = 0x1AB,
DyeItem = 0x1B5,
RequestChocoboInventory = 0x1C4,
Emote = 0x1F4,
PersistantEmoteCancel = 0x1F7,
PoseChange = 0x1F9,
PoseReapply = 0x1FA,
PoseCancel = 0x1FB,
AchievementCrit = 0x202,
AchievementComp = 0x203,
AchievementCatChat = 0x206,
DirectorInitFinish = 0x321,
SomeDirectorEvent = 0x328, // unsure what exactly triggers it, starts director when returning to instance though
EnterTerritoryEventFinished = 0x330,
AchievementCritReq = 0x3E8,
AchievementList = 0x3E9,
CompanionAction = 0x6A4,
CompanionSetBarding = 0x6A5,
CompanionActionUnlock = 0x6A6,
OpenPerformInstrumentUI = 0x71C,
};
void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& inPacket,
Entity::Player& player )
{
@ -67,13 +126,13 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in
switch( commandId )
{
case 0x01: // Toggle sheathe
case ClientTrigger::ToggleSeathe: // Toggle sheathe
{
if ( param11 == 1 )
player.setStance( Entity::Actor::Stance::Active );
player.setStance( Entity::Chara::Stance::Active );
else
{
player.setStance( Entity::Actor::Stance::Passive );
player.setStance( Entity::Chara::Stance::Passive );
player.setAutoattack( false );
}
@ -81,12 +140,12 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in
break;
}
case 0x02: // Toggle auto-attack
case ClientTrigger::ToggleAutoAttack: // Toggle auto-attack
{
if ( param11 == 1 )
{
player.setAutoattack( true );
player.setStance( Entity::Actor::Stance::Active );
player.setStance( Entity::Chara::Stance::Active );
}
else
player.setAutoattack( false );
@ -95,58 +154,75 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in
break;
}
case 0x03: // Change target
case ClientTrigger::ChangeTarget: // Change target
{
uint64_t targetId = inPacket.getValAt< uint64_t >( 0x24 );
player.changeTarget( targetId );
break;
}
case 0x65:
case ClientTrigger::Dismount:
{
player.dismount();
break;
}
case 0x68: // Remove status (clicking it off)
case ClientTrigger::RemoveStatusEffect: // Remove status (clicking it off)
{
// todo: check if status can be removed by client from exd
player.removeSingleStatusEffectById( static_cast< uint32_t >( param1 ) );
break;
}
case 0x69: // Cancel cast
case ClientTrigger::CastCancel: // Cancel cast
{
if( player.getCurrentAction() )
player.getCurrentAction()->setInterrupted();
break;
}
case 0x12E: // Set player title
case ClientTrigger::MarkPlayer: // Mark player
{
break;
}
case ClientTrigger::SetTitle: // Set player title
{
player.setTitle( static_cast< uint16_t >( param1 ) );
break;
}
case 0x12F: // Get title list
case ClientTrigger::TitleList: // Get title list
{
ZoneChannelPacket< FFXIVIpcPlayerTitleList > titleListPacket( player.getId() );
memcpy( titleListPacket.data().titleList, player.getTitleList(), sizeof( titleListPacket.data().titleList ) );
player.queuePacket( titleListPacket );
player.sendTitleList();
break;
}
case 0x133: // Update howtos seen
case ClientTrigger::UpdatedSeenHowTos: // Update howtos seen
{
uint32_t howToId = static_cast< uint32_t >( param1 );
uint32_t howToId = param11;
player.updateHowtosSeen( howToId );
break;
}
case 0x1F4: // emote
case ClientTrigger::Emote: // emote
{
uint64_t targetId = player.getTargetId();
uint32_t emoteId = inPacket.getValAt< uint32_t >( 0x24 );
player.sendToInRangeSet( ActorControlPacket144( player.getId(), Emote, emoteId, 0, 0, 0, targetId ) );
player.emote( emoteId, targetId );
break;
}
case 0xC8: // return dead
case ClientTrigger::PersistantEmoteCancel: // cancel persistant emote
{
break;
}
case ClientTrigger::PoseChange: // change pose
{
break;
}
case ClientTrigger::PoseReapply: // reapply pose
{
break;
}
case ClientTrigger::PoseCancel: // cancel pose
{
break;
}
case ClientTrigger::Return: // return dead / accept raise
{
switch ( static_cast < ResurrectType >( param1 ) )
{
@ -162,80 +238,37 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in
}
}
case 0xC9: // Finish zoning
case ClientTrigger::FinishZoning: // Finish zoning
{
switch( player.getZoningType() )
{
case ZoneingType::None:
player.sendToInRangeSet( ActorControlPacket143( player.getId(), ZoneIn, 0x01 ), true );
break;
case ZoneingType::Teleport:
player.sendToInRangeSet( ActorControlPacket143( player.getId(), ZoneIn, 0x01, 0, 0, 110 ), true );
break;
case ZoneingType::Return:
case ZoneingType::ReturnDead:
{
if( player.getStatus() == Entity::Actor::ActorStatus::Dead )
{
player.resetHp();
player.resetMp();
player.setStatus( Entity::Actor::ActorStatus::Idle );
player.sendToInRangeSet( ActorControlPacket143( player.getId(), ZoneIn, 0x01, 0x01, 0, 111 ), true );
player.sendToInRangeSet( ActorControlPacket142( player.getId(), SetStatus, static_cast< uint8_t >( Entity::Actor::ActorStatus::Idle ) ), true );
}
else
player.sendToInRangeSet( ActorControlPacket143( player.getId(), ZoneIn, 0x01, 0x00, 0, 111 ), true );
}
break;
case ZoneingType::FadeIn:
player.finishZoning();
break;
}
player.setZoningType( Common::ZoneingType::None );
case ClientTrigger::Teleport: // Teleport
{
player.unsetStateFlag( PlayerStateFlag::BetweenAreas );
player.unsetStateFlag( PlayerStateFlag::BetweenAreas1 );
player.teleportQuery( param11 );
break;
}
case 0xCA: // Teleport
{
// TODO: only register this action if enough gil is in possession
auto targetAetheryte = g_framework.getExdDataGen().get< Core::Data::Aetheryte >( param11 );
if( targetAetheryte )
{
auto fromAetheryte = g_framework.getExdDataGen().get< Core::Data::Aetheryte >( g_framework.getExdDataGen().get< Core::Data::TerritoryType >( player.getZoneId() )->aetheryte );
// calculate cost - does not apply for favorite points or homepoints neither checks for aether tickets
auto cost = static_cast< uint16_t >( ( sqrt( pow( fromAetheryte->aetherstreamX - targetAetheryte->aetherstreamX, 2 ) +
pow( fromAetheryte->aetherstreamY - targetAetheryte->aetherstreamY, 2 ) ) / 2 ) + 100 );
// cap at 999 gil
cost = cost > uint16_t{999} ? uint16_t{999} : cost;
bool insufficientGil = player.getCurrency( Inventory::CurrencyType::Gil ) < cost;
// todo: figure out what param1 really does
player.queuePacket( ActorControlPacket143( player.getId(), TeleportStart, insufficientGil ? 2 : 0, param11 ) );
if( !insufficientGil )
{
auto pActionTeleport = Action::make_ActionTeleport( player.getAsPlayer(), param11, cost );
player.setCurrentAction( pActionTeleport );
}
}
break;
}
case 0x1B5: // Dye item
case ClientTrigger::DyeItem: // Dye item
{
break;
}
case 0x321: // Director init finish
case ClientTrigger::DirectorInitFinish: // Director init finish
{
player.getCurrentZone()->onInitDirector( player );
break;
}
case ClientTrigger::SomeDirectorEvent: // Director init finish
{
player.getCurrentZone()->onSomeDirectorEvent( player );
break;
}
case ClientTrigger::EnterTerritoryEventFinished:// this may still be something else. I think i have seen it elsewhere
{
player.setOnEnterEventDone( true );
break;
}
default:
{
g_framework.getLogger().debug( "[" + std::to_string( m_pSession->getId() ) + "] Unhandled action: " +

View file

@ -21,6 +21,9 @@
#include "Actor/Player.h"
#include "Event/EventHelper.h"
#include "Zone/InstanceContent.h"
#include "Session.h"
#include "Forwards.h"
#include "Framework.h"
@ -40,7 +43,7 @@ void Core::Network::GameConnection::eventHandlerTalk( const Packets::GamePacket&
std::string eventName = "onTalk";
std::string objName = Event::getEventName( eventId );
player.sendDebug( "Actor: " +
player.sendDebug( "Chara: " +
std::to_string( actorId ) + " -> " +
std::to_string( Event::mapEventActorToRealActor( static_cast< uint32_t >( actorId ) ) ) +
" \neventId: " +
@ -52,7 +55,12 @@ void Core::Network::GameConnection::eventHandlerTalk( const Packets::GamePacket&
player.sendDebug( "Calling: " + objName + "." + eventName );
player.eventStart( actorId, eventId, Event::EventHandler::Talk, 0, 0 );
if( !g_framework.getScriptMgr().onTalk( player, actorId, eventId ) &&
if( auto instance = player.getCurrentInstance() )
{
instance->onTalk( player, eventId, actorId );
}
else if( !g_framework.getScriptMgr().onTalk( player, actorId, eventId ) &&
eventType == Event::EventHandler::EventHandlerType::Quest )
{
auto questInfo = g_framework.getExdDataGen().get< Core::Data::Quest >( eventId );
@ -75,7 +83,7 @@ void Core::Network::GameConnection::eventHandlerEmote( const Packets::GamePacket
std::string eventName = "onEmote";
std::string objName = Event::getEventName( eventId );
player.sendDebug( "Actor: " +
player.sendDebug( "Chara: " +
std::to_string( actorId ) + " -> " +
std::to_string( Event::mapEventActorToRealActor( static_cast< uint32_t >( actorId ) ) ) +
" \neventId: " +
@ -155,9 +163,22 @@ void Core::Network::GameConnection::eventHandlerEnterTerritory( const Packets::G
player.sendDebug( "Calling: " + objName + "." + eventName + " - " + std::to_string( eventId ) );
player.eventStart( player.getId(), eventId, Event::EventHandler::EnterTerritory, 0, player.getZoneId() );
player.eventStart( player.getId(), eventId, Event::EventHandler::EnterTerritory, 0, player.getZoneId(), 0 );
if( auto instance = player.getCurrentInstance() )
{
// param2 of eventStart
// 0 = default state?
// 1 = restore state?
// (^ Mordred: Nope, i don't think thats it )
player.eventStart( player.getId(), eventId, Event::EventHandler::EnterTerritory, 0, player.getZoneId(), instance->getDirectorId() & 0xFFFF );
instance->onEnterTerritory( player, eventId, param1, param2 );
}
else
{
player.eventStart( player.getId(), eventId, Event::EventHandler::EnterTerritory, 0, player.getZoneId() );
g_framework.getScriptMgr().onEnterTerritory( player, eventId, param1, param2 );
}
player.checkEvent( eventId );
}

View file

@ -6,6 +6,13 @@
#include <common/Logging/Logger.h>
#include <common/Network/PacketContainer.h>
#include <unordered_map>
#include <boost/format.hpp>
#include "Network/GameConnection.h"
#include "Session.h"
#include "Zone/TerritoryMgr.h"
#include "Zone/Zone.h"
#include "Zone/ZonePosition.h"
@ -182,7 +189,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac
}
case GmCommand::Weather:
{
targetPlayer->getCurrentZone()->setWeatherOverride( param1 );
targetPlayer->getCurrentZone()->setWeatherOverride( static_cast< Common::Weather >( param1 ) );
player.sendNotice( "Weather in Zone \"" + targetPlayer->getCurrentZone()->getName() + "\" of " +
targetPlayer->getName() + " set in range." );
break;
@ -192,8 +199,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac
if( targetPlayer->getZoneId() != player.getZoneId() )
targetPlayer->setZone( player.getZoneId() );
targetPlayer->changePosition( player.getPos().x, player.getPos().y, player.getPos().z,
player.getRotation() );
targetPlayer->changePosition( player.getPos().x, player.getPos().y, player.getPos().z, player.getRot() );
player.sendNotice( "Calling " + targetPlayer->getName() );
break;
}
@ -218,7 +224,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac
}
case GmCommand::Kill:
{
targetActor->takeDamage( 9999999 );
targetActor->getAsChara()->takeDamage( 9999999 );
player.sendNotice( "Killed " + std::to_string( targetActor->getId() ) );
break;
}
@ -268,10 +274,10 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac
}
case GmCommand::Inv:
{
if ( targetActor->getInvincibilityType() == Common::InvincibilityType::InvincibilityRefill )
targetActor->setInvincibilityType( Common::InvincibilityType::InvincibilityNone );
if( targetActor->getAsChara()->getInvincibilityType() == Common::InvincibilityType::InvincibilityRefill )
targetActor->getAsChara()->setInvincibilityType( Common::InvincibilityType::InvincibilityNone );
else
targetActor->setInvincibilityType( Common::InvincibilityType::InvincibilityRefill );
targetActor->getAsChara()->setInvincibilityType( Common::InvincibilityType::InvincibilityRefill );
player.sendNotice( "Invincibility for " + targetPlayer->getName() +
" was switched." );
@ -421,7 +427,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac
player.sendUrgent( "No zone instance found for " + std::to_string( param1 ) );
break;
}
targetPlayer->setPosition( targetPlayer->getPos() );
targetPlayer->setPos( targetPlayer->getPos() );
targetPlayer->performZoning( param1, targetPlayer->getPos(), 0 );
player.sendNotice( targetPlayer->getName() + " was warped to zone " + std::to_string( param1 ) + " (" + pZone->getName() + ")" );
}
@ -429,23 +435,23 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac
}
case GmCommand::TeriInfo:
{
auto pCurrentZone = player.getCurrentZone();
player.sendNotice( "ZoneId: " + std::to_string( player.getZoneId() ) + "\nName: " +
player.getCurrentZone()->getName() + "\nInternalName: " +
player.getCurrentZone()->getInternalName() + "\nPopCount: " +
std::to_string( player.getCurrentZone()->getPopCount() ) +
"\nCurrentWeather:" + std::to_string( player.getCurrentZone()->getCurrentWeather() ) +
"\nNextWeather:" + std::to_string( player.getCurrentZone()->getNextWeather() ) );
pCurrentZone->getName() + "\nInternalName: " +
pCurrentZone->getInternalName() + "\nPopCount: " +
std::to_string( pCurrentZone->getPopCount() ) +
"\nCurrentWeather:" + std::to_string( static_cast< uint8_t >( pCurrentZone->getCurrentWeather() ) ) +
"\nNextWeather:" + std::to_string( static_cast< uint8_t >( pCurrentZone->getNextWeather() ) ) );
break;
}
case GmCommand::Jump:
{
auto inRange = player.getInRangeActors();
for( auto actor : inRange )
{
player.changePosition( targetActor->getPos().x, targetActor->getPos().y, targetActor->getPos().z,
targetActor->getRotation() );
}
targetActor->getRot() );
player.sendNotice( "Jumping to " + targetPlayer->getName() + " in range." );
break;
}
@ -468,7 +474,7 @@ void Core::Network::GameConnection::gm2Handler( const Packets::GamePacket& inPac
g_framework.getLogger().debug( player.getName() + " used GM2 commandId: " + std::to_string( commandId ) + ", params: " + param1 );
auto targetSession = g_framework.getServerZone().getSession( param1 );
Core::Entity::ActorPtr targetActor;
Core::Entity::CharaPtr targetActor;
if( targetSession != nullptr )
{
@ -498,11 +504,11 @@ void Core::Network::GameConnection::gm2Handler( const Packets::GamePacket& inPac
{
targetPlayer->resetHp();
targetPlayer->resetMp();
targetPlayer->setStatus( Entity::Actor::ActorStatus::Idle );
targetPlayer->setStatus( Entity::Chara::ActorStatus::Idle );
targetPlayer->sendToInRangeSet( ActorControlPacket143( player.getId(), ZoneIn, 0x01, 0x01, 0, 113 ), true );
targetPlayer->sendToInRangeSet( ActorControlPacket142( player.getId(), SetStatus,
static_cast< uint8_t >( Entity::Actor::ActorStatus::Idle ) ), true );
static_cast< uint8_t >( Entity::Chara::ActorStatus::Idle ) ), true );
player.sendNotice( "Raised " + targetPlayer->getName() );
break;
}
@ -513,7 +519,7 @@ void Core::Network::GameConnection::gm2Handler( const Packets::GamePacket& inPac
player.setZone( targetPlayer->getZoneId() );
}
player.changePosition( targetActor->getPos().x, targetActor->getPos().y, targetActor->getPos().z,
targetActor->getRotation() );
targetActor->getRot() );
player.sendNotice( "Jumping to " + targetPlayer->getName() );
break;
}
@ -522,8 +528,7 @@ void Core::Network::GameConnection::gm2Handler( const Packets::GamePacket& inPac
if( targetPlayer->getZoneId() != player.getZoneId() )
targetPlayer->setZone( player.getZoneId() );
targetPlayer->changePosition( player.getPos().x, player.getPos().y, player.getPos().z,
player.getRotation() );
targetPlayer->changePosition( player.getPos().x, player.getPos().y, player.getPos().z, player.getRot() );
player.sendNotice( "Calling " + targetPlayer->getName() );
break;
}

View file

@ -7,7 +7,8 @@
#include <common/Network/PacketContainer.h>
#include <common/Network/PacketDef/Chat/ServerChatDef.h>
#include <common/Database/DatabaseDef.h>
#include <boost/format.hpp>
#include <unordered_map>
#include "Network/GameConnection.h"
#include "Zone/TerritoryMgr.h"
@ -181,11 +182,11 @@ void Core::Network::GameConnection::updatePositionHandler( const Packets::GamePa
( player.getPos().y != inPacket.getValAt< float >( 0x30 ) ) ||
( player.getPos().z != inPacket.getValAt< float >( 0x34 ) ) )
bPosChanged = true;
if( !bPosChanged && player.getRotation() == inPacket.getValAt< float >( 0x20 ) )
if( !bPosChanged && player.getRot() == inPacket.getValAt< float >( 0x20 ) )
return;
player.setRotation( inPacket.getValAt< float >( 0x20 ) );
player.setPosition( inPacket.getValAt< float >( 0x2c ),
player.setRot( inPacket.getValAt< float >( 0x20 ) );
player.setPos( inPacket.getValAt< float >( 0x2c ),
inPacket.getValAt< float >( 0x30 ),
inPacket.getValAt< float >( 0x34 ) );
@ -793,16 +794,14 @@ void Core::Network::GameConnection::tellHandler( const Packets::GamePacket& inPa
auto pTargetPlayer = pSession->getPlayer();
if( pTargetPlayer->hasStateFlag( PlayerStateFlag::BetweenAreas ) ||
pTargetPlayer->hasStateFlag( PlayerStateFlag::BetweenAreas1 ) )
if( pTargetPlayer->hasStateFlag( PlayerStateFlag::BetweenAreas ) )
{
// send error for player between areas
// TODO: implement me
return;
}
if( pTargetPlayer->hasStateFlag( PlayerStateFlag::BoundByDuty ) ||
pTargetPlayer->hasStateFlag( PlayerStateFlag::BoundByDuty1 ) )
if( pTargetPlayer->hasStateFlag( PlayerStateFlag::BoundByDuty ) )
{
// send error for player bound by duty
// TODO: implement me

View file

@ -80,11 +80,11 @@ void Core::Network::GameConnection::skillHandler( const Packets::GamePacket& inP
if( !player.actionHasCastTime( action ) )
{
g_framework.getScriptMgr().onCastFinish( player, targetActor, action );
g_framework.getScriptMgr().onCastFinish( player, targetActor->getAsChara(), action );
}
else
{
auto pActionCast = Action::make_ActionCast( player.getAsPlayer(), targetActor, action );
auto pActionCast = Action::make_ActionCast( player.getAsPlayer(), targetActor->getAsChara(), action );
player.setCurrentAction( pActionCast );
player.sendDebug( "setCurrentAction()" );
player.getCurrentAction()->onStart();

View file

@ -0,0 +1,55 @@
#ifndef _DIRECTORPLAYSCENE_H
#define _DIRECTORPLAYSCENE_H
#include <common/Network/GamePacketNew.h>
#include "Forwards.h"
namespace Core {
namespace Network {
namespace Packets {
namespace Server {
/**
* @brief The packet sent to play an event.
*/
class DirectorPlayScenePacket : public ZoneChannelPacket< FFXIVIpcDirectorPlayScene >
{
public:
DirectorPlayScenePacket( uint32_t playerId,
uint64_t actorId,
uint32_t eventId,
uint16_t scene,
uint32_t flags,
uint8_t param3,
uint32_t param4 = 0,
uint32_t param5 = 0 ) :
ZoneChannelPacket< FFXIVIpcDirectorPlayScene >( playerId, playerId )
{
initialize( actorId, eventId, scene, flags, param3, param4, param5 );
};
private:
void initialize( uint64_t actorId,
uint32_t eventId,
uint16_t scene,
uint32_t flags,
uint8_t param3,
uint32_t param4,
uint32_t param5 )
{
m_data.actorId = actorId;
m_data.eventId = eventId;
m_data.scene = scene;
m_data.flags = flags;
m_data.param3 = param3;
m_data.param4 = param4;
m_data.param5 = param5;
};
};
}
}
}
}
#endif /*_EVENTPLAY_H*/

View file

@ -20,10 +20,11 @@ public:
uint32_t eventId,
uint8_t param1 = 0,
uint8_t param2 = 0,
uint32_t param3 = 0 ) :
uint32_t param3 = 0,
uint32_t contentId = 0 ) :
ZoneChannelPacket< FFXIVIpcEventStart >( playerId, playerId )
{
initialize( actorId, eventId, param1, param2, param3 );
initialize( actorId, eventId, param1, param2, param3, contentId );
};
private:
@ -31,13 +32,15 @@ private:
uint32_t eventId,
uint8_t param1,
uint8_t param2,
uint32_t param3 )
uint32_t param3,
uint32_t contentId )
{
m_data.actorId = actorId;
m_data.eventId = eventId;
m_data.param1 = param1;
m_data.param2 = param2;
m_data.param3 = param3;
m_data.contentId = contentId;
};
};

View file

@ -21,17 +21,17 @@ class MoveActorPacket :
public ZoneChannelPacket< FFXIVIpcActorMove >
{
public:
MoveActorPacket( Entity::Actor& actor, uint8_t unk1, uint8_t unk2, uint8_t unk3, uint16_t unk4 ) :
MoveActorPacket( Entity::Chara& actor, uint8_t unk1, uint8_t unk2, uint8_t unk3, uint16_t unk4 ) :
ZoneChannelPacket< FFXIVIpcActorMove >( actor.getId(), actor.getId() )
{
initialize( actor, unk1, unk2, unk3, unk4 );
};
private:
void initialize( Entity::Actor& actor, uint8_t unk1, uint8_t unk2, uint8_t unk3, uint16_t unk4 )
void initialize( Entity::Chara& actor, uint8_t unk1, uint8_t unk2, uint8_t unk3, uint16_t unk4 )
{
m_data.rotation = Math::Util::floatToUInt8Rot( actor.getRotation() );
m_data.rotation = Math::Util::floatToUInt8Rot( actor.getRot() );
m_data.unknown_1 = unk1;
m_data.unknown_2 = unk2;
m_data.unknown_3 = unk3;

View file

@ -64,7 +64,7 @@ namespace Server {
m_data.pos.x = player.getPos().x;
m_data.pos.y = player.getPos().y;
m_data.pos.z = player.getPos().z;
m_data.rotation = Math::Util::floatToUInt16Rot( player.getRotation() );
m_data.rotation = Math::Util::floatToUInt16Rot( player.getRot() );
m_data.title = player.getTitle();
@ -76,7 +76,7 @@ namespace Server {
//m_data.u23 = 0x04;
//m_data.u24 = 256;
m_data.state = static_cast< uint8_t >( player.getStatus() );
m_data.type = 1;
m_data.modelType = player.getModelType();
if( target.getId() == player.getId() )
{
m_data.spawnIndex = 0x00;
@ -84,28 +84,31 @@ namespace Server {
else
{
m_data.spawnIndex = target.getSpawnIdForActorId( player.getId() );
if( !target.isActorSpawnIdValid( m_data.spawnIndex ) )
return;
}
// 0x20 == spawn hidden to be displayed by the spawneffect control
m_data.displayFlags = player.getStance();
if( player.getZoningType() != Common::ZoneingType::None )
{
m_data.displayFlags |= Entity::Actor::DisplayFlags::Invisible;
m_data.displayFlags |= Entity::Chara::DisplayFlags::Invisible;
}
if( player.getEquipDisplayFlags() & Core::Common::EquipDisplayFlags::HideHead )
{
m_data.displayFlags |= Entity::Actor::DisplayFlags::HideHead;
m_data.displayFlags |= Entity::Chara::DisplayFlags::HideHead;
}
if( player.getEquipDisplayFlags() & Core::Common::EquipDisplayFlags::HideWeapon )
{
m_data.displayFlags |= Entity::Actor::DisplayFlags::HideWeapon;
m_data.displayFlags |= Entity::Chara::DisplayFlags::HideWeapon;
}
if( player.getEquipDisplayFlags() & Core::Common::EquipDisplayFlags::Visor )
{
m_data.displayFlags |= Entity::Actor::DisplayFlags::Visor;
m_data.displayFlags |= Entity::Chara::DisplayFlags::Visor;
}
m_data.currentMount = player.getCurrentMount();

View file

@ -26,8 +26,8 @@ public:
PlayerStateFlagsPacket( Entity::Player& player, std::vector< Common::PlayerStateFlag > flags ) :
ZoneChannelPacket< FFXIVIpcPlayerStateFlags >( player.getId(), player.getId() )
{
uint8_t newFlags[7];
memset( newFlags, 0, 7 );
uint8_t newFlags[12];
memset( newFlags, 0, 12 );
for( auto& flag : flags )
{
@ -46,7 +46,7 @@ public:
private:
void initialize( const uint8_t* flags )
{
memcpy( m_data.flags, flags, 7 );
memcpy( m_data.flags, flags, 12 );
};
};

View file

@ -2,7 +2,7 @@
#define _UPDATEHPMPTP_H
#include <common/Network/GamePacketNew.h>
#include <Actor/Actor.h>
#include <Actor/Chara.h>
#include "Forwards.h"
namespace Core {
@ -17,14 +17,14 @@ class UpdateHpMpTpPacket :
public ZoneChannelPacket< FFXIVIpcUpdateHpMpTp >
{
public:
UpdateHpMpTpPacket( Entity::Actor& actor ) :
UpdateHpMpTpPacket( Entity::Chara& actor ) :
ZoneChannelPacket< FFXIVIpcUpdateHpMpTp >( actor.getId(), actor.getId() )
{
initialize( actor );
};
private:
void initialize( Entity::Actor& actor )
void initialize( Entity::Chara& actor )
{
m_data.hp = actor.getHp();
m_data.mp = actor.getMp();

View file

@ -4,11 +4,7 @@
#include <string>
#include <typeinfo>
#include <typeindex>
#include <Actor/Actor.h>
#include <Actor/Player.h>
#include <StatusEffect/StatusEffect.h>
#include <Zone/InstanceContent.h>
#include "Forwards.h"
#ifdef _MSC_VER
#define EXPORT __declspec( dllexport )
@ -53,14 +49,14 @@ public:
ScriptObject( effectId, typeid( StatusEffectScript ).hash_code() )
{ }
virtual void onTick( Entity::Actor& actor ) { }
virtual void onApply( Entity::Actor& actor ) { }
virtual void onRemove( Entity::Actor& actor ) { }
virtual void onExpire( Entity::Actor& actor ) { }
virtual void onPlayerCollision( Entity::Actor& actor, Entity::Actor& actorHit ) { }
virtual void onPlayerFinishCast( Entity::Actor& actor ) { }
virtual void onPlayerDamaged( Entity::Actor& actor ) { }
virtual void onPlayerDeath( Entity::Actor& actor ) { }
virtual void onTick( Entity::Chara& actor ) { }
virtual void onApply( Entity::Chara& actor ) { }
virtual void onRemove( Entity::Chara& actor ) { }
virtual void onExpire( Entity::Chara& actor ) { }
virtual void onPlayerCollision( Entity::Chara& actor, Entity::Chara& actorHit ) { }
virtual void onPlayerFinishCast( Entity::Chara& actor ) { }
virtual void onPlayerDamaged( Entity::Chara& actor ) { }
virtual void onPlayerDeath( Entity::Chara& actor ) { }
};
@ -71,9 +67,9 @@ public:
ScriptObject( abilityId, typeid( ActionScript ).hash_code() )
{ }
virtual void onStart( Entity::Actor& sourceActor, Entity::Actor& targetActor ) { }
virtual void onCastFinish( Entity::Player& player, Entity::Actor& targetActor ) { }
virtual void onInterrupt( Entity::Actor& sourceActor/*, Core::Entity::Actor targetActor*/ ) { }
virtual void onStart( Entity::Chara& sourceActor, Entity::Chara& targetActor ) { }
virtual void onCastFinish( Entity::Player& player, Entity::Chara& targetActor ) { }
virtual void onInterrupt( Entity::Chara& sourceActor/*, Core::Entity::Chara targetActor*/ ) { }
};
@ -87,7 +83,7 @@ public:
virtual void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) { }
virtual void onNpcKill( uint32_t npcId, Entity::Player& player ) { }
virtual void onEmote( uint64_t actorId, uint32_t eventId, uint32_t emoteId, Entity::Player& player ) { }
virtual void onEnterZone( Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ) { }
virtual void onEnterTerritory( Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ) { }
virtual void onWithinRange( Entity::Player& player, uint32_t eventId, uint32_t param1, float x, float y, float z ) { }
virtual void onOutsideRange( Entity::Player& player, uint32_t eventId, uint32_t param1, float x, float y, float z ) { }
virtual void onEventItem( Entity::Player& player, uint32_t eventItemId, uint32_t eventId, uint32_t castTime, uint64_t targetId ) { }
@ -117,11 +113,12 @@ class InstanceContentScript : public ScriptObject
{
public:
explicit InstanceContentScript( uint32_t instanceContentId ) :
ScriptObject( instanceContentId, typeid( InstanceContentScript ).hash_code() )
ScriptObject( uint32_t{ 0x8003 } << 16 | instanceContentId, typeid( InstanceContentScript ).hash_code() )
{ }
virtual void onInit( InstanceContent& instance ) { }
virtual void onUpdate( InstanceContent& instance, uint32_t currTime ) { }
virtual void onInit( InstanceContentPtr instance ) { }
virtual void onUpdate( InstanceContentPtr instance, uint32_t currTime ) { }
virtual void onEnterTerritory( Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ) { }
};
#endif

View file

@ -1,4 +1,7 @@
#include "NativeScriptMgr.h"
#include <boost/filesystem.hpp>
#include <common/Crypt/md5.h>
namespace Core {
namespace Scripting {

View file

@ -7,9 +7,6 @@
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/filesystem.hpp>
#include <common/Crypt/md5.h>
#include "ScriptLoader.h"

View file

@ -10,7 +10,8 @@
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winbase.h>
typedef HMODULE ModuleHandle;
#else
#include <dlfcn.h>

View file

@ -9,10 +9,9 @@
#include <common/Config/XMLConfig.h>
#include "Zone/Zone.h"
#include "Zone/InstanceContent.h"
#include "Actor/Player.h"
#include "Actor/BattleNpc.h"
#include "ServerZone.h"
#include "Event/EventHandler.h"
#include "Event/EventHelper.h"
@ -142,12 +141,6 @@ void Core::Scripting::ScriptMgr::onPlayerFirstEnterWorld( Entity::Player& player
// }
}
bool Core::Scripting::ScriptMgr::registerBnpcTemplate( std::string templateName, uint32_t bnpcBaseId,
uint32_t bnpcNameId, uint32_t modelId, std::string aiName )
{
return g_framework.getServerZone().registerBnpcTemplate( templateName, bnpcBaseId, bnpcNameId, modelId, aiName );
}
bool Core::Scripting::ScriptMgr::onTalk( Entity::Player& player, uint64_t actorId, uint32_t eventId )
{
@ -176,7 +169,7 @@ bool Core::Scripting::ScriptMgr::onEnterTerritory( Entity::Player& player, uint3
auto script = m_nativeScriptMgr->getScript< EventScript >( eventId );
if( !script )
return false;
script->onEnterZone( player, eventId, param1, param2 );
script->onEnterTerritory( player, eventId, param1, param2 );
return true;
}
@ -278,7 +271,7 @@ bool Core::Scripting::ScriptMgr::onMobKill( Entity::Player& player, uint16_t nam
return true;
}
bool Core::Scripting::ScriptMgr::onCastFinish( Entity::Player& player, Entity::ActorPtr pTarget, uint32_t actionId )
bool Core::Scripting::ScriptMgr::onCastFinish( Entity::Player& player, Entity::CharaPtr pTarget, uint32_t actionId )
{
auto script = m_nativeScriptMgr->getScript< ActionScript >( actionId );
@ -287,7 +280,7 @@ bool Core::Scripting::ScriptMgr::onCastFinish( Entity::Player& player, Entity::A
return true;
}
bool Core::Scripting::ScriptMgr::onStatusReceive( Entity::ActorPtr pActor, uint32_t effectId )
bool Core::Scripting::ScriptMgr::onStatusReceive( Entity::CharaPtr pActor, uint32_t effectId )
{
auto script = m_nativeScriptMgr->getScript< StatusEffectScript >( effectId );
@ -303,30 +296,30 @@ bool Core::Scripting::ScriptMgr::onStatusReceive( Entity::ActorPtr pActor, uint3
return false;
}
bool Core::Scripting::ScriptMgr::onStatusTick( Entity::ActorPtr pActor, Core::StatusEffect::StatusEffect& effect )
bool Core::Scripting::ScriptMgr::onStatusTick( Entity::CharaPtr pChara, Core::StatusEffect::StatusEffect& effect )
{
auto script = m_nativeScriptMgr->getScript< StatusEffectScript >( effect.getId() );
if( script )
{
if( pActor->isPlayer() )
pActor->getAsPlayer()->sendDebug( "Calling status tick for statusid: " + std::to_string( effect.getId() ) );
if( pChara->isPlayer() )
pChara->getAsPlayer()->sendDebug( "Calling status tick for statusid: " + std::to_string( effect.getId() ) );
script->onTick( *pActor );
script->onTick( *pChara );
return true;
}
return false;
}
bool Core::Scripting::ScriptMgr::onStatusTimeOut( Entity::ActorPtr pActor, uint32_t effectId )
bool Core::Scripting::ScriptMgr::onStatusTimeOut( Entity::CharaPtr pChara, uint32_t effectId )
{
auto script = m_nativeScriptMgr->getScript< StatusEffectScript >( effectId );
if( script )
{
if( pActor->isPlayer() )
pActor->getAsPlayer()->sendDebug( "Calling status timeout for statusid: " + std::to_string( effectId ) );
if( pChara->isPlayer() )
pChara->getAsPlayer()->sendDebug( "Calling status timeout for statusid: " + std::to_string( effectId ) );
script->onExpire( *pActor );
script->onExpire( *pChara );
return true;
}
@ -345,9 +338,9 @@ bool Core::Scripting::ScriptMgr::onZoneInit( ZonePtr pZone )
return false;
}
bool Core::Scripting::ScriptMgr::onInstanceInit( InstanceContent& instance )
bool Core::Scripting::ScriptMgr::onInstanceInit( InstanceContentPtr instance )
{
auto script = m_nativeScriptMgr->getScript< InstanceContentScript >( instance.getInstanceContentId() );
auto script = m_nativeScriptMgr->getScript< InstanceContentScript >( instance->getDirectorId() );
if( script )
{
script->onInit( instance );
@ -357,9 +350,10 @@ bool Core::Scripting::ScriptMgr::onInstanceInit( InstanceContent& instance )
return false;
}
bool Core::Scripting::ScriptMgr::onInstanceUpdate( InstanceContent& instance, uint32_t currTime )
bool Core::Scripting::ScriptMgr::onInstanceUpdate( InstanceContentPtr instance, uint32_t currTime )
{
auto script = m_nativeScriptMgr->getScript< InstanceContentScript >( instance.getInstanceContentId() );
auto script = m_nativeScriptMgr->getScript< InstanceContentScript >( instance->getDirectorId() );
if( script )
{
script->onUpdate( instance, currTime );
@ -369,6 +363,18 @@ bool Core::Scripting::ScriptMgr::onInstanceUpdate( InstanceContent& instance, ui
return false;
}
bool Core::Scripting::ScriptMgr::onInstanceEnterTerritory( InstanceContentPtr instance, Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 )
{
auto script = m_nativeScriptMgr->getScript< InstanceContentScript >( instance->getDirectorId() );
if( script )
{
script->onEnterTerritory( player, eventId, param1, param2 );
return true;
}
return false;
}
Scripting::NativeScriptMgr& Core::Scripting::ScriptMgr::getNativeScriptHandler()
{
return *m_nativeScriptMgr;

View file

@ -37,8 +37,6 @@ namespace Core
void onPlayerFirstEnterWorld( Entity::Player& player );
static bool registerBnpcTemplate( std::string templateName, uint32_t bnpcBaseId, uint32_t bnpcNameId, uint32_t modelId, std::string aiName );
bool onTalk( Entity::Player& player, uint64_t actorId, uint32_t eventId );
bool onEnterTerritory( Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 );
bool onWithinRange( Entity::Player& player, uint32_t eventId, uint32_t param1, float x, float y, float z );
@ -48,19 +46,20 @@ namespace Core
bool onMobKill( Entity::Player& player, uint16_t nameId );
bool onCastFinish( Entity::Player& pPlayer, Entity::ActorPtr pTarget, uint32_t actionId );
bool onCastFinish( Entity::Player& pPlayer, Entity::CharaPtr pTarget, uint32_t actionId );
bool onStatusReceive( Entity::ActorPtr pActor, uint32_t effectId );
bool onStatusTick( Entity::ActorPtr pActor, Core::StatusEffect::StatusEffect& effect );
bool onStatusTimeOut( Entity::ActorPtr pActor, uint32_t effectId );
bool onStatusReceive( Entity::CharaPtr pActor, uint32_t effectId );
bool onStatusTick( Entity::CharaPtr pActor, Core::StatusEffect::StatusEffect& effect );
bool onStatusTimeOut( Entity::CharaPtr pActor, uint32_t effectId );
bool onZoneInit( ZonePtr pZone );
bool onEventHandlerReturn( Entity::Player& player, uint32_t eventId, uint16_t subEvent, uint16_t param1, uint16_t param2, uint16_t param3 );
bool onEventHandlerTradeReturn( Entity::Player& player, uint32_t eventId, uint16_t subEvent, uint16_t param, uint32_t catalogId );
bool onInstanceInit( InstanceContent& instance );
bool onInstanceUpdate( InstanceContent& instance, uint32_t currTime );
bool onInstanceInit( InstanceContentPtr instance );
bool onInstanceUpdate( InstanceContentPtr instance, uint32_t currTime );
bool onInstanceEnterTerritory( InstanceContentPtr instance, Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 );
void loadDir( const std::string& dirname, std::set<std::string> &files, const std::string& ext );

View file

@ -39,8 +39,13 @@ foreach(_scriptDir ${children})
endif()
endforeach()
add_library("script_${_name}" MODULE "${SCRIPT_BUILD_FILES}" "${SCRIPT_INCLUDE_FILES}" "${_scriptDir}/ScriptLoader.cpp")
add_library("script_${_name}" MODULE ${SCRIPT_BUILD_FILES} "${SCRIPT_INCLUDE_FILES}" "${_scriptDir}/ScriptLoader.cpp")
target_link_libraries("script_${_name}" sapphire_zone)
cotire("script_${_name}")
if(MSVC)
target_link_libraries("script_${_name}" ${Boost_LIBRARIES})
endif()
if(MSVC)
set_target_properties("script_${_name}" PROPERTIES

View file

@ -1,11 +1,8 @@
#ifndef SAPPHIRE_SCRIPTOBJECT_H
#define SAPPHIRE_SCRIPTOBJECT_H
#include <Script/NativeScriptApi.h>
#include <Forwards.h>
#include <Actor/Actor.h>
#include <Actor/Player.h>
#include <Event/EventHelper.h>
#include <Script/NativeScriptApi.h>
enum EventFlags
{

View file

@ -1,4 +1,6 @@
#include <Script/NativeScriptApi.h>
#include "../ScriptObject.h"
#include <Actor/Player.h>
class ActionSprint3 : public ActionScript
{
@ -6,7 +8,7 @@ public:
ActionSprint3() : ActionScript( 3 )
{}
void onCastFinish( Core::Entity::Player& player, Core::Entity::Actor& targetActor ) override
void onCastFinish( Core::Entity::Player& player, Core::Entity::Chara& targetActor ) override
{
player.addStatusEffectByIdIfNotExist( 50, 20000, player, 30 );
}

View file

@ -1,4 +1,6 @@
#include <Script/NativeScriptApi.h>
#include "../ScriptObject.h"
#include <Actor/Player.h>
#define ACTION_ATTUNE 0x13
@ -39,7 +41,6 @@ public:
}, 0 );
player.unlock();
}
}

View file

@ -1,4 +1,7 @@
#include <Script/NativeScriptApi.h>
#include "../ScriptObject.h"
#include <Actor/Player.h>
#define ACTION_ATTUNE 0x13
#define ACTION_TELEPORT 0x4

View file

@ -1,4 +1,6 @@
#include <Script/NativeScriptApi.h>
#include "../ScriptObject.h"
#include <Actor/Player.h>
class CmnDefCutSceneReplay : public EventScript
{

View file

@ -1,4 +1,6 @@
#include <Script/NativeScriptApi.h>
#include "../ScriptObject.h"
#include <Actor/Player.h>
class CmnDefInnBed : public EventScript
{
@ -49,7 +51,7 @@ public:
Scene00000( player );
}
void onEnterZone( Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override
void onEnterTerritory( Entity::Player &player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override
{
Scene00100( player );
}

View file

@ -1,4 +1,6 @@
#include <Script/NativeScriptApi.h>
#include "../ScriptObject.h"
#include <Actor/Player.h>
#define ACTION_CREATE 2
#define ACTION_RENAME 3

View file

@ -1,4 +1,6 @@
#include <Script/NativeScriptApi.h>
#include "../ScriptObject.h"
#include <Actor/Player.h>
class HouFurOrchestrion : public EventScript
{

View file

@ -0,0 +1,29 @@
#include <ScriptObject.h>
#include <Zone/InstanceContent.h>
class ThePalaceoftheDeadFloors101110 : public InstanceContentScript
{
public:
ThePalaceoftheDeadFloors101110() : InstanceContentScript( 60011 )
{ }
void onInit( InstanceContentPtr instance ) override
{
instance->registerEObj( "sgvf_w_lvd_b0959", 2000608, 6527847, 4, { -300.000000f, 0.000026f, -237.000000f }, 1.000000f, 0.000000f );
// States -> vf_bextwall_on vf_bextwall_on2off vf_bextwall_off
instance->registerEObj( "sgvf_w_lvd_b0959_1", 2000608, 6544382, 4, { 301.149902f, -0.045413f, 285.247589f }, 1.000000f, 0.000000f );
// States -> vf_bextwall_on vf_bextwall_on2off vf_bextwall_off
}
void onUpdate( InstanceContentPtr instance, uint32_t currTime ) override
{
}
void onEnterTerritory( Entity::Player &player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override
{
}
};

View file

@ -0,0 +1,27 @@
#include <ScriptObject.h>
#include <Zone/InstanceContent.h>
class ThePalaceoftheDeadFloors110 : public InstanceContentScript
{
public:
ThePalaceoftheDeadFloors110() : InstanceContentScript( 60001 )
{ }
void onInit( InstanceContentPtr instance ) override
{
instance->registerEObj( "sgvf_w_lvd_b0959", 2002872, 6324883, 4, { -300.000000f, -0.000010f, -220.000000f }, 1.000000f, 0.000000f );
// States -> vf_bextwall_on vf_bextwall_on2off vf_bextwall_off
}
void onUpdate( InstanceContentPtr instance, uint32_t currTime ) override
{
}
void onEnterTerritory( Entity::Player &player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override
{
}
};

View file

@ -0,0 +1,27 @@
#include <ScriptObject.h>
#include <Zone/InstanceContent.h>
class ThePalaceoftheDeadFloors111120 : public InstanceContentScript
{
public:
ThePalaceoftheDeadFloors111120() : InstanceContentScript( 60012 )
{ }
void onInit( InstanceContentPtr instance ) override
{
instance->registerEObj( "sgvf_w_lvd_b0959", 2000608, 6535115, 4, { -300.000000f, 0.000026f, -237.000000f }, 1.000000f, 0.000000f );
// States -> vf_bextwall_on vf_bextwall_on2off vf_bextwall_off
}
void onUpdate( InstanceContentPtr instance, uint32_t currTime ) override
{
}
void onEnterTerritory( Entity::Player &player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override
{
}
};

View file

@ -0,0 +1,27 @@
#include <ScriptObject.h>
#include <Zone/InstanceContent.h>
class ThePalaceoftheDeadFloors1120 : public InstanceContentScript
{
public:
ThePalaceoftheDeadFloors1120() : InstanceContentScript( 60002 )
{ }
void onInit( InstanceContentPtr instance ) override
{
instance->registerEObj( "sgvf_w_lvd_b0959", 2000608, 6353850, 4, { -300.000000f, 0.000026f, -237.000000f }, 1.000000f, 0.000000f );
// States -> vf_bextwall_on vf_bextwall_on2off vf_bextwall_off
}
void onUpdate( InstanceContentPtr instance, uint32_t currTime ) override
{
}
void onEnterTerritory( Entity::Player &player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override
{
}
};

View file

@ -0,0 +1,27 @@
#include <ScriptObject.h>
#include <Zone/InstanceContent.h>
class ThePalaceoftheDeadFloors121130 : public InstanceContentScript
{
public:
ThePalaceoftheDeadFloors121130() : InstanceContentScript( 60013 )
{ }
void onInit( InstanceContentPtr instance ) override
{
instance->registerEObj( "sgvf_w_lvd_b0959", 2000608, 6535115, 4, { -300.000000f, 0.000026f, -237.000000f }, 1.000000f, 0.000000f );
// States -> vf_bextwall_on vf_bextwall_on2off vf_bextwall_off
}
void onUpdate( InstanceContentPtr instance, uint32_t currTime ) override
{
}
void onEnterTerritory( Entity::Player &player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override
{
}
};

View file

@ -0,0 +1,27 @@
#include <ScriptObject.h>
#include <Zone/InstanceContent.h>
class ThePalaceoftheDeadFloors131140 : public InstanceContentScript
{
public:
ThePalaceoftheDeadFloors131140() : InstanceContentScript( 60014 )
{ }
void onInit( InstanceContentPtr instance ) override
{
instance->registerEObj( "sgvf_w_lvd_b0959", 2000608, 6535683, 4, { -300.000000f, -0.000205f, -237.000000f }, 1.000000f, 0.000000f );
// States -> vf_bextwall_on vf_bextwall_on2off vf_bextwall_off
}
void onUpdate( InstanceContentPtr instance, uint32_t currTime ) override
{
}
void onEnterTerritory( Entity::Player &player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override
{
}
};

View file

@ -0,0 +1,27 @@
#include <ScriptObject.h>
#include <Zone/InstanceContent.h>
class ThePalaceoftheDeadFloors141150 : public InstanceContentScript
{
public:
ThePalaceoftheDeadFloors141150() : InstanceContentScript( 60015 )
{ }
void onInit( InstanceContentPtr instance ) override
{
instance->registerEObj( "sgvf_w_lvd_b0959", 2000608, 6535683, 4, { -300.000000f, -0.000205f, -237.000000f }, 1.000000f, 0.000000f );
// States -> vf_bextwall_on vf_bextwall_on2off vf_bextwall_off
}
void onUpdate( InstanceContentPtr instance, uint32_t currTime ) override
{
}
void onEnterTerritory( Entity::Player &player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override
{
}
};

View file

@ -0,0 +1,27 @@
#include <ScriptObject.h>
#include <Zone/InstanceContent.h>
class ThePalaceoftheDeadFloors151160 : public InstanceContentScript
{
public:
ThePalaceoftheDeadFloors151160() : InstanceContentScript( 60016 )
{ }
void onInit( InstanceContentPtr instance ) override
{
instance->registerEObj( "sgvf_w_lvd_b0959", 2000608, 6534547, 4, { -301.179504f, 0.130118f, -301.014709f }, 1.000000f, -0.000000f );
// States -> vf_bextwall_on vf_bextwall_on2off vf_bextwall_off
}
void onUpdate( InstanceContentPtr instance, uint32_t currTime ) override
{
}
void onEnterTerritory( Entity::Player &player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override
{
}
};

View file

@ -0,0 +1,27 @@
#include <ScriptObject.h>
#include <Zone/InstanceContent.h>
class ThePalaceoftheDeadFloors161170 : public InstanceContentScript
{
public:
ThePalaceoftheDeadFloors161170() : InstanceContentScript( 60017 )
{ }
void onInit( InstanceContentPtr instance ) override
{
instance->registerEObj( "sgvf_w_lvd_b0959", 2000608, 6534547, 4, { -301.179504f, 0.130118f, -301.014709f }, 1.000000f, -0.000000f );
// States -> vf_bextwall_on vf_bextwall_on2off vf_bextwall_off
}
void onUpdate( InstanceContentPtr instance, uint32_t currTime ) override
{
}
void onEnterTerritory( Entity::Player &player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override
{
}
};

View file

@ -0,0 +1,27 @@
#include <ScriptObject.h>
#include <Zone/InstanceContent.h>
class ThePalaceoftheDeadFloors171180 : public InstanceContentScript
{
public:
ThePalaceoftheDeadFloors171180() : InstanceContentScript( 60018 )
{ }
void onInit( InstanceContentPtr instance ) override
{
instance->registerEObj( "sgvf_w_lvd_b0959", 2000608, 6534547, 4, { -301.179504f, 0.130118f, -301.014709f }, 1.000000f, -0.000000f );
// States -> vf_bextwall_on vf_bextwall_on2off vf_bextwall_off
}
void onUpdate( InstanceContentPtr instance, uint32_t currTime ) override
{
}
void onEnterTerritory( Entity::Player &player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override
{
}
};

View file

@ -0,0 +1,27 @@
#include <ScriptObject.h>
#include <Zone/InstanceContent.h>
class ThePalaceoftheDeadFloors181190 : public InstanceContentScript
{
public:
ThePalaceoftheDeadFloors181190() : InstanceContentScript( 60019 )
{ }
void onInit( InstanceContentPtr instance ) override
{
instance->registerEObj( "sgvf_w_lvd_b0959", 2000608, 6534547, 4, { -301.179504f, 0.130118f, -301.014709f }, 1.000000f, -0.000000f );
// States -> vf_bextwall_on vf_bextwall_on2off vf_bextwall_off
}
void onUpdate( InstanceContentPtr instance, uint32_t currTime ) override
{
}
void onEnterTerritory( Entity::Player &player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override
{
}
};

Some files were not shown because too many files have changed in this diff Show more