diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2b3fced6..972275c8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,7 +37,8 @@ include( "cmake/compiler.cmake" )
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
git_describe(VERSION --tags --dirty=-d)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/servers/Server_Common/Version.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/src/servers/Server_Common/Version.cpp" @ONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/servers/Server_Common/Version.cpp.in"
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/servers/Server_Common/Version.cpp" @ONLY)
##########################################################################
# Common include folders
@@ -56,5 +57,10 @@ link_directories(${SERVER_COMMON_DIR})
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/libraries/sapphire/datReader)
add_subdirectory("src/servers")
+
add_subdirectory("src/libraries/sapphire/datReader")
add_subdirectory("src/libraries/sapphire/mysqlConnector")
+
+add_subdirectory("src/tools/exd_common_gen")
+add_subdirectory("src/tools/quest_parser")
+
diff --git a/bin/web/createUser.html b/bin/web/createUser.html
index 5a82c96f..5d73e5d2 100644
--- a/bin/web/createUser.html
+++ b/bin/web/createUser.html
@@ -45,7 +45,7 @@
-
+
diff --git a/bin/web/login.html b/bin/web/login.html
index 1b94f909..6d32528d 100644
--- a/bin/web/login.html
+++ b/bin/web/login.html
@@ -45,7 +45,7 @@
-
+

diff --git a/scripts/chai/global.inc b/scripts/chai/global.inc
index 48bdbe32..906a3a0b 100644
--- a/scripts/chai/global.inc
+++ b/scripts/chai/global.inc
@@ -228,6 +228,9 @@ global CURRENCY_TOMESTONELORE = 0X0E
////////////////////////////////////////////////////////////
// Skill handle types
////////////////////////////////////////////////////////////
-global STD_DAMAGE = 0X00
-global STD_HEAL = 0X01
-global STD_DOT = 0X02
\ No newline at end of file
+global STD_DAMAGE = 0X03
+global STD_HEAL = 0X04
+global STD_MP_LOSS = 0X0A
+global STD_MP_GAIN = 0X0B
+global STD_TP_LOSS = 0X0C
+global STD_TP_GAIN = 0X0D
\ No newline at end of file
diff --git a/scripts/chai/opening/OpeningGridania.chai b/scripts/chai/opening/OpeningGridania.chai
index fbaf1005..207cf8fe 100644
--- a/scripts/chai/opening/OpeningGridania.chai
+++ b/scripts/chai/opening/OpeningGridania.chai
@@ -34,7 +34,7 @@ class OpeningGridaniaDef
def Scene00000( player )
{
- player.eventPlay( this.id, 0, 0x2001, 0, 1,
+ player.eventPlay( this.id, 0, 0x04AC05, 0, 1,
fun( player, eventId, param1, param2, param3 )
{
player.setOpeningSequence( 1 );
diff --git a/scripts/chai/opening/OpeningLimsa.chai b/scripts/chai/opening/OpeningLimsa.chai
index ebae5446..f7ab44c7 100644
--- a/scripts/chai/opening/OpeningLimsa.chai
+++ b/scripts/chai/opening/OpeningLimsa.chai
@@ -72,7 +72,6 @@ class OpeningLimsaLominsaDef
player.eventPlay( this.id, 40, 1, 2, 1,
fun( player, eventId, param1, param2, param3 )
{
- player.eventFinish( eventId, UNLOCK );
if( player.getOpeningSequence() == 2 )
{
// update the instance boundaries
diff --git a/scripts/chai/opening/OpeningUldah.chai b/scripts/chai/opening/OpeningUldah.chai
index 6c19e6c4..829bab1b 100644
--- a/scripts/chai/opening/OpeningUldah.chai
+++ b/scripts/chai/opening/OpeningUldah.chai
@@ -35,7 +35,7 @@ class OpeningUldahDef
def Scene00000( player )
{
- player.eventPlay( this.id, 0, 0x2001, 0, 1,
+ player.eventPlay( this.id, 0, 0x04AC05, 0, 1,
fun( player, eventId, param1, param2, param3 )
{
player.setOpeningSequence( 1 );
diff --git a/scripts/chai/quest/ManFst003.chai b/scripts/chai/quest/ManFst003.chai
index 8d592cff..403d18d3 100644
--- a/scripts/chai/quest/ManFst003.chai
+++ b/scripts/chai/quest/ManFst003.chai
@@ -9,11 +9,11 @@
// Start NPC: 1001140
// End NPC: 1000100
-class ManFst003Def
+class ManFst003Def
{
def ManFst003Def()
{
- // Basic quest information
+ // Basic quest information
this.name = "Close to Home";
this.id = 65659;
@@ -24,13 +24,13 @@ class ManFst003Def
// GetQuestUI8BL
// GetQuestUI8CH
- // Steps in this quest ( 0 is before accepting,
+ // Steps in this quest ( 0 is before accepting,
// 1 is first, 255 means ready for turning it in
this.SEQ_0 = 0;
this.SEQ_1 = 1;
this.SEQ_FINISH = 255;
- // Quest rewards
+ // Quest rewards
this.RewardExpFactor = 100;
this.RewardGil = 107;
@@ -74,7 +74,6 @@ class ManFst003Def
def checkQuestCompletion( player, varIdx )
{
- print( varIdx );
if (varIdx == 3)
{
player.questMessage(this.id, 1, 0, 0, 0 );
@@ -118,8 +117,8 @@ class ManFst003Def
player.eventPlay( this.id, 1, 0x0EFB/*flags*/, 0/*unk*/, 0/*unk*/,
fun( player, eventId, param1, param2, param3 )
{
- player.setQuestUI8AL( ManFst004.id, 1 );
- ManFst003.checkQuestCompletion( player, 1 );
+ player.setQuestUI8AL( ManFst003.id, 1 );
+ ManFst003.checkQuestCompletion( player, 0 );
});
}
@@ -128,7 +127,7 @@ class ManFst003Def
player.eventPlay( this.id, 2, 0, 0, 0,
fun( player, eventId, param1, param2, param3 )
{
- player.setQuestUI8BH( ManFst004.id, 1 );
+ player.setQuestUI8BH( ManFst003.id, 1 );
ManFst003.checkQuestCompletion( player, 3 );
});
}
@@ -207,8 +206,8 @@ class ManFst003Def
player.eventPlay( this.id, 100, 0x0EFB, 0, 0,
fun( player, eventId, param1, param2, param3 )
{
- player.setQuestUI8CH( ManFst004.id, 0 ); // remove key item, since we have just traded it
- player.setQuestUI8BL( ManFst004.id, 1 );
+ player.setQuestUI8CH( ManFst003.id, 0 ); // remove key item, since we have just traded it
+ player.setQuestUI8BL( ManFst003.id, 1 );
ManFst003.checkQuestCompletion(player, 2 );
});
}
@@ -237,7 +236,6 @@ class ManFst003Def
},
fun( player, eventId, additional ) {},
eventId );
- player.unlock();
}
else if( actor == this.ACTOR2 )
{
@@ -257,4 +255,3 @@ class ManFst003Def
};
GLOBAL ManFst003 = ManFst003Def();
-
diff --git a/scripts/chai/quest/ManSea001.chai b/scripts/chai/quest/ManSea001.chai
index c3af3b76..8c060bf2 100644
--- a/scripts/chai/quest/ManSea001.chai
+++ b/scripts/chai/quest/ManSea001.chai
@@ -51,11 +51,12 @@ class ManSea001Def
// Available Scenes in this quest, not necessarly all are used
def Scene00000( player )
{
- player.eventPlay( this.id, 0, HIDE_HOTBAR, 0/*unk*/, 0/*unk*/,
+ player.eventPlay( this.id, 0, 0x2000, 0, 0,
fun( player, eventId, param1, param2, param3 )
{
if( param2 == 1 )
{
+ player.setOpeningSequence( 2 );
ManSea001.Scene00001( player );
}
});
@@ -63,7 +64,7 @@ class ManSea001Def
def Scene00001( player )
{
- player.eventPlay( this.id, 1, HIDE_HOTBAR, 0/*unk*/, 0/*unk*/,
+ player.eventPlay( this.id, 1, 0xF8482EFB, 0, 0,
fun( player, eventId, param1, param2, param3 )
{
ManSea001.Scene00002( player );
@@ -81,13 +82,13 @@ class ManSea001Def
def Scene00003( player )
{
- player.eventPlay( this.id, 3, NONE, 0/*unk*/, 0/*unk*/,
+ player.eventPlay( this.id, 3, NONE, 0, 0,
fun( player, eventId, param1, param2, param3 )
{
player.questUpdate( ManSea001.id, 0x01 ); // add quest to player.
// update the instance boundaries, call to the opening event
- //player.eventPlay( ManSea001.OPENING_EVENT_HANDLER, 0x1E, HIDE_HOTBAR, 1, 0);
+ player.eventPlay( ManSea001.OPENING_EVENT_HANDLER, 0x1E, 0x2001, 1, 0);
});
}
@@ -107,7 +108,7 @@ class ManSea001Def
def Scene00006( player )
{
- player.eventPlay( this.id, 6, NONE, 0/*unk*/, 0/*unk*/,
+ player.eventPlay( this.id, 6, 0x20, 0/*unk*/, 0/*unk*/,
fun( player, eventId, param1, param2, param3 )
{
if( param2 == 1 )
@@ -141,7 +142,7 @@ class ManSea001Def
def Scene00011( player )
{
- player.eventPlay( this.id, 11, NONE, 0, 0,
+ player.eventPlay( this.id, 11, 0x2c02, 0, 0,
fun( player, eventId, param1, param2, param3 )
{
ManSea001.Scene00012( player );
@@ -150,7 +151,7 @@ class ManSea001Def
def Scene00012( player )
{
- player.eventPlay( this.id, 12, NONE, 0, 0,
+ player.eventPlay( this.id, 12, 0x20, 0, 0,
fun( player, eventId, param1, param2, param3 )
{
if( param2 == 1 )
diff --git a/scripts/chai/quest/ManWil001.chai b/scripts/chai/quest/ManWil001.chai
index 1799e45a..da55f8c1 100644
--- a/scripts/chai/quest/ManWil001.chai
+++ b/scripts/chai/quest/ManWil001.chai
@@ -9,25 +9,25 @@
// Start NPC: 1003987
// End NPC: 1003988
-class ManWil001Def
+class ManWil001Def
{
//////////////////////////////////////////////////////////////////////
// default ctor
def ManWil001Def()
{
- // Basic quest information
+ // Basic quest information
this.name = "Coming to Ul'dah";
this.id = 66130;
// Quest vars / flags used
// GetQuestUI8AL
- // Steps in this quest ( 0 is before accepting,
+ // Steps in this quest ( 0 is before accepting,
// 1 is first, 255 means ready for turning it in
this.SEQ_0 = 0;
this.SEQ_FINISH = 255;
- // Quest rewards
+ // Quest rewards
this.RewardExpFactor = 50;
this.RewardGil = 103;
@@ -49,11 +49,12 @@ class ManWil001Def
// Available Scenes in this quest, not necessarly all are used
def Scene00000( player )
{
- player.eventPlay( this.id, 0, 0, 0, 0,
+ player.eventPlay( this.id, 0, 0x2000, 0, 0,
fun( player, eventId, param1, param2, param3 )
{
if( param2 == 1 ) // accept quest
{
+ player.setOpeningSequence( 2 );
ManWil001.Scene00001( player );
}
});
@@ -61,7 +62,7 @@ class ManWil001Def
def Scene00001( player )
{
- player.eventPlay( this.id, 1, 0, 0, 0,
+ player.eventPlay( this.id, 1, 0xF8482EFB, 0, 0,
fun( player, eventId, param1, param2, param3 )
{
ManWil001.Scene00002( player );
@@ -70,11 +71,11 @@ class ManWil001Def
def Scene00002( player )
{
- player.eventPlay( this.id, 2, 0, 0, 0,
+ player.eventPlay( this.id, 2, NONE, 0, 0,
fun( player, eventId, param1, param2, param3 )
{
- player.questUpdate( ManWil001.id, ManWil001Obj.SEQ_FINISH );// add quest to player.
- player.eventPlay( ManWil001.OPENING_EVENT_HANDLER, 0x1E, 0x2001, 0, 0 );
+ player.questUpdate( ManWil001.id, ManWil001.SEQ_FINISH );// add quest to player.
+ player.eventPlay( ManWil001.OPENING_EVENT_HANDLER, 0x1E, 0x2001, 0, 0 );
});
}
@@ -85,7 +86,7 @@ class ManWil001Def
def Scene00004( player )
{
- player.eventPlay( this.id, 4, 0, 0, 0,
+ player.eventPlay( this.id, 4, 0x2c02, 0, 0,
fun( player, eventId, param1, param2, param3 )
{
ManWil001.Scene00005( player );
@@ -94,7 +95,7 @@ class ManWil001Def
def Scene00005( player )
{
- player.eventPlay( this.id, 5, 0/*flags*/, 0/*unk*/, 0/*unk*/,
+ player.eventPlay( this.id, 5, 0x20/*flags*/, 0/*unk*/, 0/*unk*/,
fun( player, eventId, param1, param2, param3 )
{
if( param2 == 1 ) // clicked finish button
diff --git a/scripts/chai/skill/thm/skillDef_147.chai b/scripts/chai/skill/thm/skillDef_147.chai
new file mode 100644
index 00000000..e36950a1
--- /dev/null
+++ b/scripts/chai/skill/thm/skillDef_147.chai
@@ -0,0 +1,18 @@
+// Skill Name: Fire II
+// Skill ID: 147
+
+class skillDef_147Def
+{
+ def skillDef_147Def()
+ {
+
+ }
+
+ def onFinish( player, target )
+ {
+ player.handleScriptSkill( STD_DAMAGE, 147, 80, 0, target );
+ }
+
+};
+
+GLOBAL skillDef_147 = skillDef_147Def();
\ No newline at end of file
diff --git a/src/servers/Server_Common/Common.h b/src/servers/Server_Common/Common.h
index 752eb711..dc4c5fff 100644
--- a/src/servers/Server_Common/Common.h
+++ b/src/servers/Server_Common/Common.h
@@ -383,6 +383,29 @@ namespace Core {
instance,
};
+ enum TerritoryIntendedUseType : uint8_t //ToDo: Add The Rest of The Territory Types and Have Better Names For Them
+ {
+ Town = 0,
+ OpenWorld = 1,
+ Inn = 2,
+ Dungeon = 3,
+ JailArea = 5,
+ OpeningArea = 6,
+ BeforeTrialDung = 7,
+ AllianceRaid = 8,
+ OpenWorldInstanceBattle = 9,
+ Trial = 10,
+ HousingArea = 13,
+ HousingPrivateArea = 14,
+ MSQPrivateArea = 15,
+ Raids = 16,
+ RaidFights = 17,
+ ChocoboTutorial = 21,
+ Wedding = 22,
+ BeginnerTutorial = 27,
+ PalaceOfTheDead = 31,
+ };
+
enum CharaLook : uint8_t
{
Race = 0x00,
@@ -548,7 +571,7 @@ namespace Core {
Unaspected = 7 // Doesn't imply magical unaspected damage - could be unaspected physical
};
- enum struct ActionType : int8_t
+ enum class ActionType : int8_t
{
WeaponOverride = -1, // Needs more investigation (takes the damage type of the equipped weapon)?
Unknown_0 = 0,
@@ -581,7 +604,7 @@ namespace Core {
GpGain = 14
};
- enum ActionHitSeverityType : uint8_t
+ enum class ActionHitSeverityType : uint8_t
{
NormalDamage = 0,
CritHeal = 0,
@@ -591,6 +614,19 @@ namespace Core {
CritDirectHitDamage = 3
};
+ enum class ActionCollisionType : uint8_t
+ {
+ None,
+ SingleTarget,
+ Circle,
+ Cone,
+ Box,
+ Unknown,
+ Unknown2,
+ PersistentArea, // for when you set aoe like asylum
+ Unknown3
+ };
+
enum HandleActionType : uint8_t
{
Event,
@@ -605,8 +641,16 @@ namespace Core {
StdDot,
};
+ enum InvincibilityType : uint8_t
+ {
+ InvincibilityNone,
+ InvincibilityRefill,
+ InvincibilityStayAlive,
+ };
+
enum struct PlayerStateFlag : uint8_t
{
+ SomeFlag,
NoCombat,
Combat,
Casting,
@@ -614,9 +658,9 @@ namespace Core {
StatusAffliction1,
Occupied,
Occupied1,
-
Occupied2,
Occupied3,
+
BoundByDuty,
Occupied4,
DuelingArea,
@@ -627,6 +671,7 @@ namespace Core {
PreparingToCraft,
Gathering,
Fishing,
+
BeingRaised,
BetweenAreas,
Stealthed,
@@ -637,9 +682,9 @@ namespace Core {
BetweenAreas1,
SystemError,
LoggingOut,
+
InvalidLocation,
WaitingForDuty,
-
BoundByDuty1,
Mounting,
WatchingCutscene,
@@ -657,9 +702,9 @@ namespace Core {
FreeTrail,
BeingMoved,
Mounting2,
-
StatusAffliction3,
StatusAffliction4,
+
RegisteringRaceOrMatch,
WaitingForRaceOrMatch,
WaitingForTripleTriadMatch,
diff --git a/src/servers/Server_Common/Exd/ExdData.cpp b/src/servers/Server_Common/Exd/ExdData.cpp
index 0c5fd98f..40e6e28d 100644
--- a/src/servers/Server_Common/Exd/ExdData.cpp
+++ b/src/servers/Server_Common/Exd/ExdData.cpp
@@ -323,70 +323,74 @@ bool Core::Data::ExdData::loadActionInfo()
continue;
}
- std::string name = getField< std::string >( fields, 0 ); // 0
- uint8_t category = getField< uint8_t >( fields, 3 ); // 3
+ std::string name = getField< std::string >( fields, 0 ); // 0
+ uint8_t category = getField< uint8_t >( fields, 3 ); // 3
- int8_t class_job = getField< int8_t >( fields, 10 ); // 10
- uint8_t unlock_level = getField< uint8_t >( fields, 11 ); // 11
- int8_t range = getField< int8_t >( fields, 13 ); // 13
- bool can_target_self = getField< bool >( fields, 14 ); // 14
- bool can_target_party = getField< bool>( fields, 15 ); // 15
- bool can_target_friendly = getField< bool >( fields, 16 ); // 16
- bool can_target_enemy = getField< bool >( fields, 17 ); // 17
+ int8_t class_job = getField< int8_t >( fields, 10 ); // 10
+ uint8_t unlock_level = getField< uint8_t >( fields, 11 ); // 11
+ int8_t range = getField< int8_t >( fields, 13 ); // 13
+ bool can_target_self = getField< bool >( fields, 14 ); // 14
+ bool can_target_party = getField< bool>( fields, 15 ); // 15
+ bool can_target_friendly = getField< bool >( fields, 16 ); // 16
+ bool can_target_enemy = getField< bool >( fields, 17 ); // 17
- bool is_aoe = getField< bool >( fields, 20 ); // 20
+ bool is_ground_aoe = getField< bool >( fields, 20 ); // 20
// Column 23: Seems to be related to raising skills (Raise, Resurrection, Reanimate)
- bool can_target_ko = getField< bool >( fields, 24 ); // 24
+ bool can_target_ko = getField< bool >( fields, 24 ); // 24
- uint8_t aoe_type = getField< uint8_t >( fields, 26 ); // 26
- uint8_t radius = getField< uint8_t >( fields, 27 ); // 27
+ uint8_t aoe_type = getField< uint8_t >( fields, 26 ); // 26
+ uint8_t aoe_range = getField< uint8_t >( fields, 27 ); // 27
+ uint8_t aoe_width = getField< uint8_t >( fields, 28 ); // 28
- uint8_t points_type = getField< uint8_t >( fields, 30 ); // 30
- uint16_t points_cost = getField< uint16_t >( fields, 31 ); // 31
+ uint8_t points_type = getField< uint8_t >( fields, 30 ); // 30
+ uint16_t points_cost = getField< uint16_t >( fields, 31 ); // 31
- uint32_t instantval = getField< bool >( fields, 35 ); // 35
- uint16_t cast_time = getField< uint16_t >( fields, 36 ); // 36
- uint16_t recast_time = getField< uint16_t >( fields, 37 ); // 37
+ bool is_instant = getField< bool >( fields, 35 ); // 35
+ uint16_t cast_time = getField< uint16_t >( fields, 36 ); // 36
+ uint16_t recast_time = getField< uint16_t >( fields, 37 ); // 37
- int8_t model = getField< int8_t >( fields, 39 ); // 39: Action model
- uint8_t aspect = getField< uint8_t >( fields, 40 ); // 40: Action aspect
+ int8_t model = getField< int8_t >( fields, 39 ); // 39
+ uint8_t aspect = getField< uint8_t >( fields, 40 ); // 40
- uint8_t typeshift = 0x6;
- uint8_t mask = 1 << typeshift;
- instantval &= mask;
- bool final = ( instantval & mask ) == mask;
- bool is_instant = final;
+ uint16_t toggle_status_id = getField< uint16_t >( fields, 42 ); // 42
+ bool affects_position = getField< bool >( fields, 47 ); // 47
-
+ info->id = id;
+ info->name = name;
+ info->category = category;
- info->id = id;
- info->name = name;
- info->category = category;
-
- info->class_job = class_job;
- info->unlock_level = unlock_level;
- info->range = range;
- info->can_target_self = can_target_self;
- info->can_target_party = can_target_party;
+ info->class_job = class_job;
+ info->unlock_level = unlock_level;
+ info->range = range;
+ info->can_target_self = can_target_self;
+ info->can_target_party = can_target_party;
info->can_target_friendly = can_target_friendly;
- info->can_target_enemy = can_target_enemy;
+ info->can_target_enemy = can_target_enemy;
- info->can_target_ko = can_target_ko;
+ info->can_target_ko = can_target_ko;
- info->is_aoe = is_aoe;
+ info->is_ground_aoe = is_ground_aoe;
- info->aoe_type = aoe_type;
- info->radius = radius;
- info->points_type = points_type;
- info->points_cost = points_cost;
+ info->aoe_type = aoe_type;
+ info->aoe_range = aoe_range;
+ info->aoe_width = aoe_width;
- info->is_instant = is_instant;
- info->cast_time = cast_time * 100;
- info->recast_time = recast_time * 100;
+ info->points_type = points_type;
+ info->points_cost = points_cost;
- info->model = model;
- info->aspect = aspect;
+ info->is_instant = is_instant;
+ info->cast_time = cast_time * 100;
+ info->recast_time = recast_time * 100;
+
+ info->model = model;
+ info->aspect = aspect;
+
+ info->toggle_status_id = toggle_status_id;
+ info->affects_position = affects_position;
+
+ // If action type is SingleTarget with an AoE radius set, or if action type isn't SingleTarget
+ info->is_aoe = ( info->aoe_type == 1 && info->aoe_width != 0 ) || ( info->aoe_type != 1 );
m_actionInfoMap.emplace( std::make_pair( info->id, info ) );
diff --git a/src/servers/Server_Common/Exd/ExdData.h b/src/servers/Server_Common/Exd/ExdData.h
index a6376550..f34e6b35 100644
--- a/src/servers/Server_Common/Exd/ExdData.h
+++ b/src/servers/Server_Common/Exd/ExdData.h
@@ -233,12 +233,13 @@ namespace Core {
bool can_target_friendly; // 16
bool can_target_enemy; // 17
- bool is_aoe; // 20
+ bool is_ground_aoe; // 20
bool can_target_ko; // 24
uint8_t aoe_type; // 26
- uint8_t radius; // 27
+ uint8_t aoe_range; // 27
+ uint8_t aoe_width; // 28
uint8_t points_type; // 30
uint16_t points_cost; // 31
@@ -249,6 +250,12 @@ namespace Core {
int8_t model; // 39
uint8_t aspect; // 40
+
+ uint16_t toggle_status_id; // 42
+
+ bool affects_position; // 47
+
+ bool is_aoe; // Internal only
};
struct EventItemInfo
diff --git a/src/servers/Server_Zone/Action/ActionCast.cpp b/src/servers/Server_Zone/Action/ActionCast.cpp
index 16d07d8b..df132950 100644
--- a/src/servers/Server_Zone/Action/ActionCast.cpp
+++ b/src/servers/Server_Zone/Action/ActionCast.cpp
@@ -50,7 +50,7 @@ void Core::Action::ActionCast::onStart()
m_pSource->getAsPlayer()->sendDebug( "onStart()" );
m_startTime = Util::getTimeMs();
- GamePacketNew< FFXIVIpcActorCast, ServerZoneIpcType > castPacket( getId() );
+ GamePacketNew< FFXIVIpcActorCast, ServerZoneIpcType > castPacket( m_pSource->getId() );
castPacket.data().action_id = m_id;
castPacket.data().unknown = 1;
diff --git a/src/servers/Server_Zone/Action/ActionCollision.cpp b/src/servers/Server_Zone/Action/ActionCollision.cpp
new file mode 100644
index 00000000..a0ab372e
--- /dev/null
+++ b/src/servers/Server_Zone/Action/ActionCollision.cpp
@@ -0,0 +1,137 @@
+#include
+#include
+#include
+
+#include "ActionCollision.h"
+#include
+#include
+#include
+#include
+
+using namespace Core::Entity;
+using namespace Core::Common;
+
+// todo: add AoE actor limits (16, 32)
+
+bool ActionCollision::isActorApplicable( ActorPtr actorPtr, TargetFilter targetFilter )
+{
+ bool actorApplicable = false;
+ switch ( targetFilter )
+ {
+ case TargetFilter::All:
+ {
+ actorApplicable = true;
+ break;
+ }
+ case TargetFilter::Players:
+ {
+ actorApplicable = actorPtr->isPlayer();
+ break;
+ }
+ case TargetFilter::Allies:
+ {
+ // todo: implement ally NPCs
+ actorApplicable = !actorPtr->isMob();
+ break;
+ }
+ case TargetFilter::Party:
+ {
+ // todo: implement party
+ actorApplicable = actorPtr->isPlayer();
+ break;
+ }
+ case TargetFilter::Enemies:
+ {
+ actorApplicable = actorPtr->isMob();
+ break;
+ }
+ }
+
+ return ( actorApplicable && actorPtr->isAlive() );
+}
+
+std::set< Core::Entity::ActorPtr > ActionCollision::getActorsHitFromAction( FFXIVARR_POSITION3 aoePosition, std::set< ActorPtr > actorsInRange, boost::shared_ptr< Core::Data::ActionInfo > actionInfo, TargetFilter targetFilter )
+{
+ std::set< ActorPtr > actorsCollided;
+
+ switch ( static_cast< ActionCollisionType >( actionInfo->aoe_type ) )
+ {
+ case ActionCollisionType::None:
+ case ActionCollisionType::SingleTarget:
+ {
+ // This is actually needed. There is "splash damage" in actions marked as single target.
+ // Notice how we're using aoe_width. How collision works for SingleTarget is unknown as of now.
+ for ( auto pActor : actorsInRange )
+ {
+ // Make sure actor exists. If it doesn't we done goofed.
+ assert( pActor );
+
+ // Don't bother wasting on collision if actor doesn't apply for it
+ if ( !isActorApplicable( pActor, targetFilter ) )
+ continue;
+
+ // Test our collision from actor with the area generated by the action from the AoE data
+ if ( radiusCollision( pActor->getPos(), aoePosition, actionInfo->aoe_width ) )
+ {
+ // Add it to the actors collided with the area
+ actorsCollided.insert( pActor );
+ }
+ }
+ break;
+ }
+ case ActionCollisionType::Circle:
+ {
+ for ( auto pActor : actorsInRange )
+ {
+ assert( pActor );
+
+ if ( !isActorApplicable( pActor, targetFilter ) )
+ continue;
+
+ if ( radiusCollision( pActor->getPos(), aoePosition, actionInfo->aoe_range ) )
+ {
+ actorsCollided.insert( pActor );
+ }
+ }
+ break;
+ }
+ case ActionCollisionType::Box:
+ {
+ for ( auto pActor : actorsInRange )
+ {
+ assert( pActor );
+
+ if ( !isActorApplicable( pActor, targetFilter ) )
+ continue;
+
+ if ( boxCollision( pActor->getPos(), aoePosition, actionInfo->aoe_width, actionInfo->aoe_range ) )
+ {
+ // todo: does this actually work?
+
+ actorsCollided.insert( pActor );
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return actorsCollided;
+}
+
+bool ActionCollision::radiusCollision( FFXIVARR_POSITION3 actorPosition, FFXIVARR_POSITION3 aoePosition, uint16_t radius )
+{
+ return Core::Math::Util::distance( actorPosition.x, actorPosition.y, actorPosition.z,
+ aoePosition.x, aoePosition.y, aoePosition.z ) <= radius;
+}
+
+bool ActionCollision::boxCollision( FFXIVARR_POSITION3 actorPosition, FFXIVARR_POSITION3 aoePosition, uint16_t width, uint16_t height )
+{
+ return actorPosition.x < aoePosition.x + width &&
+ actorPosition.x > aoePosition.x &&
+ actorPosition.y < aoePosition.y + height &&
+ actorPosition.y > aoePosition.y;
+}
\ No newline at end of file
diff --git a/src/servers/Server_Zone/Action/ActionCollision.h b/src/servers/Server_Zone/Action/ActionCollision.h
new file mode 100644
index 00000000..cff25934
--- /dev/null
+++ b/src/servers/Server_Zone/Action/ActionCollision.h
@@ -0,0 +1,37 @@
+#ifndef _ACTIONCOLLISION_H
+#define _ACTIONCOLLISION_H
+
+#include
+
+#include
+#include "Action.h"
+
+namespace Core {
+ namespace Entity {
+
+ enum class TargetFilter
+ {
+ All, // All actors in the AoE are applicable for collision
+ Players, // Only players
+ Allies, // Only allies (players, ally NPCs)
+ Party, // Only party members
+ Enemies // Only enemies
+ };
+
+ class ActionCollision
+ {
+ public:
+
+ static bool isActorApplicable( ActorPtr actorPtr, TargetFilter targetFilter );
+ static std::set< ActorPtr > getActorsHitFromAction( Common::FFXIVARR_POSITION3 aoePosition, std::set< ActorPtr > actorsInRange, boost::shared_ptr< Data::ActionInfo > actionInfo, TargetFilter targetFilter );
+
+ private:
+ static bool radiusCollision( Common::FFXIVARR_POSITION3 actorPosition, Common::FFXIVARR_POSITION3 aoePosition, uint16_t radius );
+ static bool boxCollision( Common::FFXIVARR_POSITION3 actorPosition, Common::FFXIVARR_POSITION3 aoePosition, uint16_t width, uint16_t height );
+
+ };
+
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/servers/Server_Zone/Action/ActionTeleport.cpp b/src/servers/Server_Zone/Action/ActionTeleport.cpp
index 22705d71..998cf8fc 100644
--- a/src/servers/Server_Zone/Action/ActionTeleport.cpp
+++ b/src/servers/Server_Zone/Action/ActionTeleport.cpp
@@ -45,7 +45,7 @@ void Core::Action::ActionTeleport::onStart()
m_startTime = Util::getTimeMs();
- GamePacketNew< FFXIVIpcActorCast, ServerZoneIpcType > castPacket( getId() );
+ GamePacketNew< FFXIVIpcActorCast, ServerZoneIpcType > castPacket( m_pSource->getId() );
castPacket.data().action_id = 5;
castPacket.data().unknown = 1;
diff --git a/src/servers/Server_Zone/Action/EventAction.cpp b/src/servers/Server_Zone/Action/EventAction.cpp
index 0de8a4de..00116ed4 100644
--- a/src/servers/Server_Zone/Action/EventAction.cpp
+++ b/src/servers/Server_Zone/Action/EventAction.cpp
@@ -53,8 +53,7 @@ void Core::Action::EventAction::onStart()
if( m_pSource->isPlayer() )
{
m_pSource->sendToInRangeSet( control, true );
- m_pSource->getAsPlayer()->setStateFlag( PlayerStateFlag::NoCombat );
- m_pSource->getAsPlayer()->setStateFlag( PlayerStateFlag::Occupied1 );
+ m_pSource->getAsPlayer()->setStateFlag( PlayerStateFlag::SomeFlag );
m_pSource->getAsPlayer()->sendStateFlags();
}
else
@@ -85,8 +84,7 @@ void Core::Action::EventAction::onFinish()
if( m_pSource->isPlayer() )
{
- m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::NoCombat );
- m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::Occupied1 );
+ m_pSource->getAsPlayer()->unsetStateFlag( PlayerStateFlag::SomeFlag );
m_pSource->getAsPlayer()->sendStateFlags();
m_pSource->sendToInRangeSet( control, true );
}
diff --git a/src/servers/Server_Zone/Actor/Actor.cpp b/src/servers/Server_Zone/Actor/Actor.cpp
index 1b4e3c38..977cdd6e 100644
--- a/src/servers/Server_Zone/Actor/Actor.cpp
+++ b/src/servers/Server_Zone/Actor/Actor.cpp
@@ -1,6 +1,7 @@
#include
#include
#include
+#include
#include "src/servers/Server_Zone/Forwards.h"
#include "src/servers/Server_Zone/Action/Action.h"
@@ -15,11 +16,14 @@
#include "src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffect.h"
+#include "src/servers/Server_Zone/Action/ActionCollision.h"
#include "src/servers/Server_Zone/ServerZone.h"
#include "src/servers/Server_Zone/Session.h"
+#include "CalcBattle.h"
#include "Player.h"
extern Core::ServerZone g_serverZone;
+extern Core::Data::ExdData g_exdData;
using namespace Core::Common;
using namespace Core::Network::Packets;
@@ -53,13 +57,13 @@ std::string Core::Entity::Actor::getName() const
/*! \return true if the actor is of type player */
bool Core::Entity::Actor::isPlayer() const
{
- return ( m_type == ActorType::Player ? true : false );
+ return m_type == ActorType::Player;
}
/*! \return true if the actor is of type mob */
bool Core::Entity::Actor::isMob() const
{
- return ( m_type == ActorType::BattleNpc ? true : false );
+ return m_type == ActorType::BattleNpc;
}
/*! \return list of actors currently in range */
@@ -109,6 +113,12 @@ uint16_t Core::Entity::Actor::getGp() const
return m_gp;
}
+/*! \return current invincibility type */
+InvincibilityType Core::Entity::Actor::getInvincibilityType() const
+{
+ return m_invincibilityType;
+}
+
/*! \return current class or job */
Core::Common::ClassJob Core::Entity::Actor::getClass() const
{
@@ -161,32 +171,44 @@ uint32_t Core::Entity::Actor::getMaxMp() const
void Core::Entity::Actor::resetHp()
{
m_hp = getMaxHp();
+ sendStatusUpdate( true );
}
/*! \return reset mp to current max mp */
void Core::Entity::Actor::resetMp()
{
m_mp = getMaxMp();
+ sendStatusUpdate( true );
}
/*! \param hp amount to set ( caps to maxHp ) */
void Core::Entity::Actor::setHp( uint32_t hp )
{
m_hp = hp < getMaxHp() ? hp : getMaxHp();
+ sendStatusUpdate( true );
}
/*! \param mp amount to set ( caps to maxMp ) */
void Core::Entity::Actor::setMp( uint32_t mp )
{
m_mp = mp < getMaxMp() ? mp : getMaxMp();
+ sendStatusUpdate( true );
}
-/*! \param mp amount to set ( caps to maxMp ) */
+/*! \param gp amount to set*/
void Core::Entity::Actor::setGp( uint32_t gp )
{
m_gp = gp;
+ sendStatusUpdate( true );
}
+/*! \param type invincibility type to set */
+void Core::Entity::Actor::setInvincibilityType( Common::InvincibilityType type )
+{
+ m_invincibilityType = type;
+}
+
+
/*! \return current status of the actor */
Core::Entity::Actor::ActorStatus Core::Entity::Actor::getStatus() const
{
@@ -240,10 +262,7 @@ bool Core::Entity::Actor::face( const Common::FFXIVARR_POSITION3& p )
setRotation( newRot );
- if( oldRot != newRot )
- return true;
-
- return false;
+ return oldRot != newRot ? true : false;
}
/*!
@@ -331,8 +350,18 @@ void Core::Entity::Actor::takeDamage( uint32_t damage )
{
if( damage >= m_hp )
{
- m_hp = 0;
- die();
+ switch( m_invincibilityType ) {
+ case InvincibilityNone:
+ setHp( 0 );
+ die();
+ break;
+ case InvincibilityRefill:
+ resetHp();
+ break;
+ case InvincibilityStayAlive:
+ setHp( 0 );
+ break;
+ }
}
else
m_hp -= damage;
@@ -620,6 +649,135 @@ void Core::Entity::Actor::autoAttack( ActorPtr pTarget )
}
}
+/*!
+ChaiScript Skill Handler.
+
+\param GamePacketPtr to send
+\param bool should be send to self?
+*/
+void Core::Entity::Actor::handleScriptSkill( uint32_t type, uint32_t actionId, uint64_t param1, uint64_t param2, Entity::Actor& pTarget )
+{
+
+ if ( isPlayer() )
+ {
+ getAsPlayer()->sendDebug( std::to_string( pTarget.getId() ) );
+ getAsPlayer()->sendDebug( "Handle script skill type: " + std::to_string( type ) );
+ }
+
+ auto actionInfoPtr = g_exdData.getActionInfo( 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.
+
+ GamePacketNew< FFXIVIpcEffect, ServerZoneIpcType > effectPacket( getId() );
+ effectPacket.data().targetId = pTarget.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( getRotation() );
+ effectPacket.data().effectTarget = pTarget.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 = param1;
+ effectPacket.data().effects[0].effectType = ActionEffectType::Damage;
+ effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalDamage;
+ effectPacket.data().effects[0].unknown_3 = 7;
+
+ if ( !actionInfoPtr->is_aoe )
+ {
+ // If action on this specific target is valid...
+ if ( isPlayer() && !ActionCollision::isActorApplicable( pTarget.shared_from_this(), TargetFilter::Enemies ) )
+ break;
+
+ pTarget.takeDamage( static_cast< uint32_t >( param1 ) );
+ pTarget.onActionHostile( shared_from_this() );
+ sendToInRangeSet( effectPacket, true );
+ }
+ else
+ {
+
+ std::set< ActorPtr > actorsCollided = ActionCollision::getActorsHitFromAction( pTarget.getPos(), getInRangeActors( true ), actionInfoPtr, TargetFilter::Enemies );
+
+ for ( auto pHitActor : actorsCollided )
+ {
+ effectPacket.data().targetId = pHitActor->getId();
+ effectPacket.data().effectTarget = pHitActor->getId();
+
+ sendToInRangeSet( effectPacket, true ); // todo: send to range of what? ourselves? when mob script hits this is going to be lacking
+ pHitActor->takeDamage( static_cast< uint32_t >( param1 ) );
+ pHitActor->onActionHostile( shared_from_this() );
+
+ // Debug
+ if ( isPlayer() )
+ {
+ if ( pHitActor->isPlayer() ) {
+ getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) + " (" + pHitActor->getName() + ")" );
+ }
+ else
+ getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) );
+ }
+ }
+ }
+
+ break;
+ }
+
+ case ActionEffectType::Heal:
+ {
+ uint32_t calculatedHeal = Data::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->is_aoe )
+ {
+ if ( isPlayer() && !ActionCollision::isActorApplicable( pTarget.shared_from_this(), TargetFilter::Allies ) )
+ break;
+
+ sendToInRangeSet( effectPacket, true );
+ pTarget.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)
+
+ std::set< ActorPtr > actorsCollided = ActionCollision::getActorsHitFromAction( pTarget.getPos(), getInRangeActors( true ), actionInfoPtr, TargetFilter::Allies );
+
+ for ( auto pHitActor : actorsCollided )
+ {
+ effectPacket.data().targetId = pTarget.getId();
+ effectPacket.data().effectTarget = pHitActor->getId();
+
+ sendToInRangeSet( effectPacket, true );
+ pHitActor->heal( calculatedHeal );
+
+ // Debug
+ if ( isPlayer() )
+ {
+ if ( pHitActor->isPlayer() ) {
+ getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) + " (" + pHitActor->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::Actor::addStatusEffect( StatusEffect::StatusEffectPtr pEffect )
{
@@ -629,7 +787,8 @@ void Core::Entity::Actor::addStatusEffect( StatusEffect::StatusEffectPtr pEffect
/*! \param StatusEffectPtr to be applied to the actor */
void Core::Entity::Actor::addStatusEffectById( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param )
{
- StatusEffect::StatusEffectPtr effect( new StatusEffect::StatusEffect( id, pSource.shared_from_this(), shared_from_this(), duration, 3000 ) );
+ StatusEffect::StatusEffectPtr effect( new StatusEffect::StatusEffect( id, pSource.shared_from_this(),
+ shared_from_this(), duration, 3000 ) );
effect->setParam( param );
addStatusEffect( effect );
}
@@ -639,7 +798,8 @@ void Core::Entity::Actor::addStatusEffectByIdIfNotExist( uint32_t id, int32_t du
{
if( !m_pStatusEffectContainer->hasStatusEffect( id ) )
{
- StatusEffect::StatusEffectPtr effect( new StatusEffect::StatusEffect( id, pSource.shared_from_this(), shared_from_this(), duration, 3000 ) );
+ StatusEffect::StatusEffectPtr effect( new StatusEffect::StatusEffect( id, pSource.shared_from_this(),
+ shared_from_this(), duration, 3000 ) );
effect->setParam( param );
addStatusEffect( effect );
}
diff --git a/src/servers/Server_Zone/Actor/Actor.h b/src/servers/Server_Zone/Actor/Actor.h
index de6b9118..215ec666 100644
--- a/src/servers/Server_Zone/Actor/Actor.h
+++ b/src/servers/Server_Zone/Actor/Actor.h
@@ -150,6 +150,8 @@ protected:
Action::ActionPtr m_pCurrentAction;
/*! Container for status effects */
StatusEffect::StatusEffectContainerPtr m_pStatusEffectContainer;
+ /*! Invincibility type */
+ Common::InvincibilityType m_invincibilityType;
public:
Actor();
@@ -199,6 +201,8 @@ public:
uint16_t getGp() const;
+ Common::InvincibilityType getInvincibilityType() const;
+
Common::ClassJob getClass() const;
uint8_t getClassAsInt() const;
@@ -225,12 +229,16 @@ public:
void setGp( uint32_t gp );
+ void setInvincibilityType( Common::InvincibilityType type );
+
void die();
ActorStatus getStatus() const;
void setStatus( ActorStatus status );
+ void handleScriptSkill( uint32_t type, uint32_t actionId, uint64_t param1, uint64_t param2, Entity::Actor& target );
+
virtual void autoAttack( ActorPtr pTarget );
virtual void spawn( PlayerPtr pTarget ) {}
diff --git a/src/servers/Server_Zone/Actor/BattleNpc.cpp b/src/servers/Server_Zone/Actor/BattleNpc.cpp
index b9891203..d8f098e9 100644
--- a/src/servers/Server_Zone/Actor/BattleNpc.cpp
+++ b/src/servers/Server_Zone/Actor/BattleNpc.cpp
@@ -54,6 +54,7 @@ Core::Entity::BattleNpc::BattleNpc( uint32_t modelId, uint32_t nameid, const Com
m_type = ActorType::BattleNpc;
m_mode = MODE_IDLE;
+ m_targetId = INVALID_GAME_OBJECT_ID;
m_maxHp = 150;
m_maxMp = 100;
@@ -82,6 +83,8 @@ Core::Entity::BattleNpc::BattleNpc( uint32_t modelId, uint32_t nameid, const Com
m_mobType = mobType;
+ m_invincibilityType = InvincibilityType::InvincibilityNone;
+
//m_type = static_cast< Common::ActorType >( type );
}
@@ -229,7 +232,7 @@ void Core::Entity::BattleNpc::setOwner( Core::Entity::PlayerPtr pPlayer )
}
else
{
- GamePacketNew< FFXIVIpcActorOwner, ServerZoneIpcType > setOwnerPacket(getId(), INVALID_GAME_OBJECT_ID);
+ GamePacketNew< FFXIVIpcActorOwner, ServerZoneIpcType > setOwnerPacket(getId(), INVALID_GAME_OBJECT_ID );
setOwnerPacket.data().type = 0x01;
setOwnerPacket.data().actorId = INVALID_GAME_OBJECT_ID;
sendToInRangeSet( setOwnerPacket );
@@ -251,15 +254,15 @@ bool Core::Entity::BattleNpc::moveTo( Common::FFXIVARR_POSITION3& pos )
// reached destination
return true;
- float rot = Math::Util::calcAngFrom(getPos().x, getPos().z, pos.x, pos.z);
+ 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 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 );
+ float z = static_cast< float >( sinf( angle ) * 1.1f );
Common::FFXIVARR_POSITION3 newPos;
diff --git a/src/servers/Server_Zone/Actor/BattleNpc.h b/src/servers/Server_Zone/Actor/BattleNpc.h
index d13d082b..f74f9536 100644
--- a/src/servers/Server_Zone/Actor/BattleNpc.h
+++ b/src/servers/Server_Zone/Actor/BattleNpc.h
@@ -104,7 +104,7 @@ private:
uint32_t m_unk2;
std::set< HateListEntry* > m_hateList;
ActorPtr m_pOwner;
- int32_t m_timeOfDeath;
+ uint32_t m_timeOfDeath;
uint32_t m_mobType;
};
diff --git a/src/servers/Server_Zone/Actor/CalcBattle.cpp b/src/servers/Server_Zone/Actor/CalcBattle.cpp
index f33c2e5c..5bc0d252 100644
--- a/src/servers/Server_Zone/Actor/CalcBattle.cpp
+++ b/src/servers/Server_Zone/Actor/CalcBattle.cpp
@@ -5,6 +5,7 @@
#include "Player.h"
#include
+using namespace Core::Data;
using namespace Core::Entity;
extern Core::Data::ExdData g_exdData;
@@ -44,9 +45,6 @@ float CalcBattle::calculateBaseStat( PlayerPtr pPlayer )
base = 1.63f * level + 121.02f;
// ARR Base Stat Formula (Off by one in several cases)
else
- // Old: base = 0.053f * ( level * level ) + ( 1.022f * level ) - 0.907f + 20;
- // V1: base = 0.0523f * ( level * level ) + ( 1.04f * level ) + 19.405f;
- // V2: base = 0.05223f * ( level * level ) + ( 1.0405f * level ) + 19.405f;
base = 0.052602f * ( level * level ) + ( 1.0179f * level ) + 19.6f;
return base;
@@ -83,7 +81,7 @@ uint32_t CalcBattle::calculateMaxHp( PlayerPtr pPlayer )
else if ( level >= 50 )
approxBaseHp = 1700 + ( ( level - 50 ) * ( 1700 * 1.04325f ) );
else
- approxBaseHp = paramGrowthInfoIt->second.mp_const * 0.7596f;
+ approxBaseHp = paramGrowthInfoIt->second.mp_const * 0.7667f;
uint16_t result = static_cast< uint16_t >( floor( jobModHp * ( approxBaseHp / 100.0f ) ) + floor( hpMod / 100.0f * ( vitStat - baseStat ) ) );
@@ -113,7 +111,6 @@ uint32_t CalcBattle::calculateMaxMp( PlayerPtr pPlayer )
return result;
}
-
uint32_t CalcBattle::calculateHealValue( PlayerPtr pPlayer, uint32_t potency )
{
auto classInfoIt = g_exdData.m_classJobInfoMap.find( pPlayer->getClass() );
diff --git a/src/servers/Server_Zone/Actor/CalcBattle.h b/src/servers/Server_Zone/Actor/CalcBattle.h
index f4885725..0cbde694 100644
--- a/src/servers/Server_Zone/Actor/CalcBattle.h
+++ b/src/servers/Server_Zone/Actor/CalcBattle.h
@@ -5,8 +5,10 @@
#include "Actor.h"
+using namespace Core::Entity;
+
namespace Core {
-namespace Entity {
+namespace Data {
class CalcBattle
{
diff --git a/src/servers/Server_Zone/Actor/Player.cpp b/src/servers/Server_Zone/Actor/Player.cpp
index 49bc2ad3..54b7270e 100644
--- a/src/servers/Server_Zone/Actor/Player.cpp
+++ b/src/servers/Server_Zone/Actor/Player.cpp
@@ -82,6 +82,7 @@ Core::Entity::Player::Player() :
m_onlineStatus = 0;
m_queuedZoneing = nullptr;
m_status = ActorStatus::Idle;
+ m_invincibilityType = InvincibilityType::InvincibilityNone;
memset( m_questTracking, 0, sizeof( m_questTracking ) );
memset( m_name, 0, sizeof( m_name ) );
@@ -192,7 +193,7 @@ void Core::Entity::Player::prepareZoning( uint16_t targetZone, bool fadeOut, uin
preparePacket.data().targetZone = targetZone;
preparePacket.data().fadeOutTime = fadeOutTime;
preparePacket.data().animation = animation;
- preparePacket.data().fadeOut = fadeOut == true ? 1 : 0;
+ preparePacket.data().fadeOut = static_cast< uint8_t >( fadeOut ? 1 : 0 );
queuePacket( preparePacket );
}
@@ -216,7 +217,7 @@ void Core::Entity::Player::calculateStats()
auto paramGrowthInfo = paramGrowthInfoIt->second;
// TODO: put formula somewhere else...
- float base = CalcBattle::calculateBaseStat( getAsPlayer() );
+ float base = Data::CalcBattle::calculateBaseStat( getAsPlayer() );
m_baseStats.str = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_str ) / 100 ) + tribeInfo.mod_str );
m_baseStats.dex = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_dex ) / 100 ) + tribeInfo.mod_dex );
@@ -232,9 +233,9 @@ void Core::Entity::Player::calculateStats()
m_baseStats.attackPotMagic = paramGrowthInfo.base_secondary;
m_baseStats.healingPotMagic = paramGrowthInfo.base_secondary;
- m_baseStats.max_mp = CalcBattle::calculateMaxMp( getAsPlayer() );
+ m_baseStats.max_mp = Data::CalcBattle::calculateMaxMp( getAsPlayer() );
- m_baseStats.max_hp = CalcBattle::calculateMaxHp( getAsPlayer() );
+ m_baseStats.max_hp = Data::CalcBattle::calculateMaxHp( getAsPlayer() );
if( m_mp > m_baseStats.max_mp )
m_mp = m_baseStats.max_mp;
@@ -398,7 +399,7 @@ void Core::Entity::Player::setZone( uint32_t zoneId )
if( isLogin() )
{
GamePacketNew< FFXIVIpcCFAvailableContents, ServerZoneIpcType > contentFinderList( getId() );
- for( auto i = 0; i < 72; i++ )
+ for( auto i = 0; i < sizeof( contentFinderList.data().contents ); i++ )
{
// unlock all contents for now
contentFinderList.data().contents[i] = 0xFF;
@@ -632,7 +633,9 @@ void Core::Entity::Player::gainExp( uint32_t amount )
if( ( currentExp + amount ) >= neededExpToLevel )
{
// levelup
- amount = ( currentExp + amount - neededExpToLevel ) > neededExpToLevelplus1 ? neededExpToLevelplus1 - 1 : ( currentExp + amount - neededExpToLevel );
+ amount = ( currentExp + amount - neededExpToLevel ) > neededExpToLevelplus1 ?
+ neededExpToLevelplus1 - 1 :
+ ( currentExp + amount - neededExpToLevel );
setExp( amount );
gainLevel();
queuePacket( ActorControlPacket143( getId(), UpdateUiExp, static_cast< uint8_t >( getClass() ), amount ) );
@@ -791,50 +794,6 @@ void Core::Entity::Player::setLevelForClass( uint8_t level, Core::Common::ClassJ
setSyncFlag( PlayerSyncFlags::ExpLevel );
}
-void Core::Entity::Player::eventActionStart( uint32_t eventId,
- uint32_t action,
- ActionCallback finishCallback,
- ActionCallback interruptCallback,
- uint64_t additional )
-{
- Action::ActionPtr pEventAction( new Action::EventAction( shared_from_this(), eventId, action,
- finishCallback, interruptCallback, additional ) );
-
- setCurrentAction( pEventAction );
- auto pEvent = getEvent( eventId );
-
- if( !pEvent && getEventCount() )
- {
- // We're trying to play a nested event, need to start it first.
- eventStart( getId(), eventId, Event::Event::Nest, 0, 0 );
- pEvent = getEvent( eventId );
- }
- else if( !pEvent )
- {
- g_log.error( "Could not find event " + std::to_string( eventId ) + ", event has not been started!" );
- return;
- }
-
- if( pEvent )
- pEvent->setPlayedScene( true );
- pEventAction->onStart();
-}
-
-
-void Core::Entity::Player::eventItemActionStart( uint32_t eventId,
- uint32_t action,
- ActionCallback finishCallback,
- ActionCallback interruptCallback,
- uint64_t additional )
-{
- Action::ActionPtr pEventItemAction( new Action::EventItemAction( shared_from_this(), eventId, action,
- finishCallback, interruptCallback, additional ) );
-
- setCurrentAction( pEventItemAction );
-
- pEventItemAction->onStart();
-}
-
void Core::Entity::Player::sendModel()
{
ModelEquipPacket modelEquip( getAsPlayer() );
@@ -846,6 +805,12 @@ uint32_t Core::Entity::Player::getModelForSlot( Inventory::EquipSlot slot )
return m_modelEquip[slot];
}
+void Core::Entity::Player::setModelForSlot( Inventory::EquipSlot slot, uint32_t val )
+{
+ m_modelEquip[slot] = val;
+ setSyncFlag( PlayerSyncFlags::Status );
+}
+
uint64_t Core::Entity::Player::getModelMainWeapon() const
{
return m_modelMainWeapon;
@@ -973,7 +938,7 @@ void Core::Entity::Player::setGcRankAt( uint8_t index, uint8_t rank )
setSyncFlag( PlayerSyncFlags::GC );
}
-const uint8_t * Core::Entity::Player::getStateFlags() const
+const uint8_t* Core::Entity::Player::getStateFlags() const
{
return m_stateFlags;
}
@@ -1086,21 +1051,16 @@ void Core::Entity::Player::update( int64_t currTime )
m_lastUpdate = currTime;
- // @TODO needs to happen in a if check. Don't want autoattacking while an action is being performed.
if( !checkAction() )
{
- if( m_targetId )
+ if( m_targetId && m_currentStance == Entity::Actor::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 )
{
- if( isAutoattackOn() &&
- actor->getId() == m_targetId &&
- actor->isAlive() &&
- mainWeap &&
- m_currentStance == Entity::Actor::Stance::Active
- )
+ if( actor->getId() == m_targetId && actor->isAlive() && mainWeap )
{
// default autoattack range
// TODO make this dependant on bnpc size
@@ -1514,114 +1474,6 @@ void Core::Entity::Player::autoAttack( ActorPtr pTarget )
}
-void Core::Entity::Player::handleScriptSkill( uint32_t type, uint32_t actionId, uint64_t param1, uint64_t param2, Entity::Actor& pTarget )
-{
- sendDebug( std::to_string( pTarget.getId() ) );
- sendDebug( "Handle script skill type: " + std::to_string( type ) );
-
- auto actionInfoPtr = g_exdData.getActionInfo( actionId );
-
-
- switch( type )
- {
-
- case Core::Common::HandleSkillType::StdDamage:
- {
- sendDebug( "STD_DAMAGE" );
-
- GamePacketNew< FFXIVIpcEffect, ServerZoneIpcType > effectPacket( getId() );
- effectPacket.data().targetId = pTarget.getId();
- effectPacket.data().actionAnimationId = actionId;
- effectPacket.data().unknown_2 = 1; // This seems to have an effect on the "double-cast finish" animation
- // effectPacket.data().unknown_3 = 1;
- effectPacket.data().actionTextId = actionId;
- effectPacket.data().numEffects = 1;
- effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() );
- effectPacket.data().effectTarget = pTarget.getId();
- effectPacket.data().effects[0].value = static_cast< int16_t >( param1 );
- effectPacket.data().effects[0].effectType = ActionEffectType::Damage;
- effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalDamage;
- effectPacket.data().effects[0].unknown_3 = 7;
-
- sendToInRangeSet( effectPacket, true );
-
- if ( !pTarget.isAlive() )
- break;
-
- pTarget.takeDamage( static_cast< uint32_t >( param1 ) );
- pTarget.onActionHostile( shared_from_this() );
- break;
- }
-
- case Core::Common::HandleSkillType::StdHeal:
- {
- uint32_t calculatedHeal = CalcBattle::calculateHealValue( getAsPlayer(), static_cast< uint32_t >( param1 ) );
-
- sendDebug( "STD_HEAL" );
-
- GamePacketNew< FFXIVIpcEffect, ServerZoneIpcType > effectPacket( getId() );
- effectPacket.data().targetId = pTarget.getId();
- effectPacket.data().actionAnimationId = actionId;
- effectPacket.data().unknown_2 = 1; // This seems to have an effect on the "double-cast finish" animation
- // effectPacket.data().unknown_3 = 1;
- effectPacket.data().actionTextId = actionId;
- effectPacket.data().numEffects = 1;
- effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() );
- effectPacket.data().effectTarget = pTarget.getId();
- effectPacket.data().effects[0].value = calculatedHeal;
- effectPacket.data().effects[0].effectType = ActionEffectType::Heal;
- effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalHeal;
- effectPacket.data().effects[0].unknown_3 = 7;
-
- sendToInRangeSet( effectPacket, true );
-
- if ( !pTarget.isAlive() )
- break;
-
- // todo: get proper packets: the following was just kind of thrown together from what we know
- // also toss AoE to another spot and make it generic
-
- if ( actionInfoPtr->is_aoe )
- {
- for ( auto pCurAct : m_inRangePlayers )
- {
- assert( pCurAct );
- if ( !pCurAct->isAlive() )
- break;
-
- if ( Math::Util::distance( pTarget.getPos().x, pTarget.getPos().y, pTarget.getPos().z, pCurAct->getPos().x, pCurAct->getPos().y, pCurAct->getPos().z ) <= actionInfoPtr->radius )
- {
- GamePacketNew< FFXIVIpcEffect, ServerZoneIpcType > effectPacket( pCurAct->getId() );
- effectPacket.data().targetId = pCurAct->getId();
- effectPacket.data().unknown_1 = 1; // the magic trick for getting it to work
- effectPacket.data().unknown_2 = 1;
- effectPacket.data().unknown_8 = 1;
- effectPacket.data().unknown_5 = 1;
- effectPacket.data().actionAnimationId = actionId;
- effectPacket.data().actionTextId = 0;
- effectPacket.data().numEffects = 1;
- effectPacket.data().effectTarget = pCurAct->getId();
- effectPacket.data().effects[0].value = calculatedHeal;
- effectPacket.data().effects[0].effectType = ActionEffectType::Heal;
- effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalHeal;
- effectPacket.data().effects[0].unknown_3 = 7;
-
- pCurAct->sendToInRangeSet( effectPacket, true );
- pCurAct->heal( calculatedHeal );
- sendDebug( "AoE hit actor " + pCurAct->getName() );
- }
- }
- }
-
- pTarget.heal( calculatedHeal );
- break;
- }
-
- default:
- break;
- }
-}
-
/////////////////////////////
// Content Finder
@@ -1644,9 +1496,7 @@ uint32_t Core::Entity::Player::getCFPenaltyMinutes() const
// check if penalty timestamp already passed current time
if (currentTimestamp > endTimestamp)
- {
return 0;
- }
auto deltaTime = endTimestamp - currentTimestamp;
return static_cast< uint32_t > ( ceil( static_cast< float > (deltaTime) / 60 ) );
diff --git a/src/servers/Server_Zone/Actor/Player.h b/src/servers/Server_Zone/Actor/Player.h
index 907a5916..1001251a 100644
--- a/src/servers/Server_Zone/Actor/Player.h
+++ b/src/servers/Server_Zone/Actor/Player.h
@@ -103,7 +103,7 @@ public:
/*! load data for currently active quests */
bool loadActiveQuests();
/*! update quest ( register it as active quest if new ) */
- void updateQuest( uint16_t questId, uint16_t sequence );
+ void updateQuest( uint16_t questId, uint8_t sequence );
/*! return true if quest is currently active */
bool hasQuest( uint16_t questId );
/*! return the current quest sequence */
@@ -218,6 +218,8 @@ public:
const uint32_t * getModelArray() const;
/*! return the equipment model in a specified equipment slot */
uint32_t getModelForSlot( Inventory::EquipSlot slot );
+ /*! set the equipment model in a specified equipment slot */
+ void setModelForSlot( Inventory::EquipSlot slot, uint32_t val );
/*! return the current amount of currency of type */
uint32_t getCurrency( uint8_t type ) const;
/*! add amount to the currency of type */
@@ -487,8 +489,6 @@ public:
void setAutoattack( bool mode );
bool isAutoattackOn() const;
- void handleScriptSkill( uint32_t type, uint32_t actionId, uint64_t param1, uint64_t param2, Entity::Actor& target );
-
// Content Finder handling
//////////////////////////////////////////////////////////////////////////////////////////////////////
/*! Get an unix time when the player can register into content finder again. */
diff --git a/src/servers/Server_Zone/Actor/PlayerEvent.cpp b/src/servers/Server_Zone/Actor/PlayerEvent.cpp
index f0bf77fe..721456e9 100644
--- a/src/servers/Server_Zone/Actor/PlayerEvent.cpp
+++ b/src/servers/Server_Zone/Actor/PlayerEvent.cpp
@@ -18,6 +18,10 @@
#include "src/servers/Server_Zone/Network/PacketWrappers/EventPlayPacket.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/EventFinishPacket.h"
+#include "src/servers/Server_Zone/Action/EventAction.h"
+#include "src/servers/Server_Zone/Action/EventItemAction.h"
+
+#include "src/servers/Server_Zone/Event/Event.h"
#include "src/servers/Server_Zone/Event/Event.h"
#include "Server_Zone/ServerZone.h"
@@ -230,6 +234,50 @@ void Core::Entity::Player::eventFinish( uint32_t eventId, uint32_t freePlayer )
}
}
+void Core::Entity::Player::eventActionStart( uint32_t eventId,
+ uint32_t action,
+ ActionCallback finishCallback,
+ ActionCallback interruptCallback,
+ uint64_t additional )
+{
+ Action::ActionPtr pEventAction( new Action::EventAction( shared_from_this(), eventId, action,
+ finishCallback, interruptCallback, additional ) );
+
+ setCurrentAction( pEventAction );
+ auto pEvent = getEvent( eventId );
+
+ if( !pEvent && getEventCount() )
+ {
+ // We're trying to play a nested event, need to start it first.
+ eventStart( getId(), eventId, Event::Event::Nest, 0, 0 );
+ pEvent = getEvent( eventId );
+ }
+ else if( !pEvent )
+ {
+ g_log.error( "Could not find event " + std::to_string( eventId ) + ", event has not been started!" );
+ return;
+ }
+
+ if( pEvent )
+ pEvent->setPlayedScene( true );
+ pEventAction->onStart();
+}
+
+
+void Core::Entity::Player::eventItemActionStart( uint32_t eventId,
+ uint32_t action,
+ ActionCallback finishCallback,
+ ActionCallback interruptCallback,
+ uint64_t additional )
+{
+ Action::ActionPtr pEventItemAction( new Action::EventItemAction( shared_from_this(), eventId, action,
+ finishCallback, interruptCallback, additional ) );
+
+ setCurrentAction( pEventItemAction );
+
+ pEventItemAction->onStart();
+}
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Core::Entity::Player::onLogin()
diff --git a/src/servers/Server_Zone/Actor/PlayerQuest.cpp b/src/servers/Server_Zone/Actor/PlayerQuest.cpp
index c6038f61..668460a7 100644
--- a/src/servers/Server_Zone/Actor/PlayerQuest.cpp
+++ b/src/servers/Server_Zone/Actor/PlayerQuest.cpp
@@ -74,7 +74,7 @@ bool Core::Entity::Player::loadActiveQuests()
void Core::Entity::Player::finishQuest( uint16_t questId )
{
- int8_t idx = getQuestIndex( static_cast< uint16_t >( questId ) );
+ int16_t idx = getQuestIndex( questId );
if( ( idx != -1 ) && ( m_activeQuests[idx] != nullptr ) )
{
@@ -100,7 +100,7 @@ void Core::Entity::Player::finishQuest( uint16_t questId )
m_questTracking[ii] = -1;
}
- boost::shared_ptr pQuest = m_activeQuests[idx];
+ boost::shared_ptr< QuestActive > pQuest = m_activeQuests[idx];
m_activeQuests[idx].reset();
m_freeQuestIdxQueue.push( idx );
@@ -123,7 +123,7 @@ void Core::Entity::Player::unfinishQuest( uint16_t questId )
void Core::Entity::Player::removeQuest( uint16_t questId )
{
- int8_t idx = getQuestIndex( static_cast< uint16_t >( questId ) );
+ int16_t idx = getQuestIndex( questId );
if( ( idx != -1 ) && ( m_activeQuests[idx] != nullptr ) )
{
@@ -973,7 +973,7 @@ uint8_t Core::Entity::Player::getQuestSeq( uint16_t questId )
return 0;
}
-void Core::Entity::Player::updateQuest( uint16_t questId, uint16_t sequence )
+void Core::Entity::Player::updateQuest( uint16_t questId, uint8_t sequence )
{
if( hasQuest( questId ) )
{
diff --git a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp
index 6a4f6e84..70c413c0 100644
--- a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp
+++ b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp
@@ -239,25 +239,6 @@ void Core::DebugCommandHandler::set( char * data, Core::Entity::PlayerPtr pPlaye
else
pPlayer->setClassJob( static_cast ( id ) );
}
- else if( subCommand == "no" )
- {
- int32_t id;
-
- sscanf( params.c_str(), "%d", &id );
-
- uint8_t typeshift = 0x6;
- uint8_t mask = 1 << typeshift;
- id &= mask;
- bool final = ( id & mask ) == mask;
- pPlayer->sendDebug( std::to_string(final) );
- }
- else if( subCommand == "aaah" )
- {
- int32_t id;
- sscanf( params.c_str(), "%d", &id );
-
- pPlayer->sendDebug( std::to_string( pPlayer->actionHasCastTime( id ) ) );
- }
else if ( subCommand == "cfpenalty" )
{
int32_t minutes;
@@ -273,6 +254,20 @@ void Core::DebugCommandHandler::set( char * data, Core::Entity::PlayerPtr pPlaye
pPlayer->setEorzeaTimeOffset( timestamp );
pPlayer->sendNotice( "Eorzea time offset: " + std::to_string( timestamp ) );
}
+ else if ( subCommand == "model" )
+ {
+ uint32_t slot;
+ uint32_t val;
+ sscanf( params.c_str(), "%d %d", &slot, &val );
+
+ pPlayer->setModelForSlot( static_cast( slot ), val );
+ pPlayer->sendModel();
+ pPlayer->sendDebug( "Model updated" );
+ }
+ else
+ {
+ pPlayer->sendUrgent( subCommand + " is not a valid SET command." );
+ }
}
@@ -378,6 +373,10 @@ void Core::DebugCommandHandler::add( char * data, Core::Entity::PlayerPtr pPlaye
pPlayer->queuePacket(controlPacket);*/
}
+ else
+ {
+ pPlayer->sendUrgent( subCommand + " is not a valid ADD command." );
+ }
}
@@ -419,6 +418,10 @@ void Core::DebugCommandHandler::get( char * data, Core::Entity::PlayerPtr pPlaye
std::to_string( map_id ) + "\nZoneID: " +
std::to_string( pPlayer->getCurrentZone()->getId() ) + "\n" );
}
+ else
+ {
+ pPlayer->sendUrgent( subCommand + " is not a valid GET command." );
+ }
}
@@ -486,6 +489,7 @@ void Core::DebugCommandHandler::nudge( char * data, Entity::PlayerPtr pPlayer, b
void Core::DebugCommandHandler::serverInfo( char * data, Core::Entity::PlayerPtr pPlayer, boost::shared_ptr< Core::DebugCommand > command )
{
- pPlayer->sendDebug( "SapphireServer " + Version::VERSION + " - " + Version::GIT_HASH );
+ pPlayer->sendDebug( "SapphireServer " + Version::VERSION + "\nRev: " + Version::GIT_HASH );
+ pPlayer->sendDebug( "Compiled: " __DATE__ " " __TIME__ );
pPlayer->sendDebug( "Sessions: " + std::to_string( g_serverZone.getSessionCount() ) );
}
diff --git a/src/servers/Server_Zone/Inventory/Inventory.cpp b/src/servers/Server_Zone/Inventory/Inventory.cpp
index bffe043b..2b552583 100644
--- a/src/servers/Server_Zone/Inventory/Inventory.cpp
+++ b/src/servers/Server_Zone/Inventory/Inventory.cpp
@@ -440,14 +440,14 @@ bool Core::Inventory::removeCrystal( CrystalType type, uint32_t amount )
return true;
}
-bool Core::Inventory::isObtainable( uint32_t catalogId, uint16_t quantity )
+bool Core::Inventory::isObtainable( uint32_t catalogId, uint8_t quantity )
{
return true;
}
-int16_t Core::Inventory::addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint16_t quantity )
+int16_t Core::Inventory::addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint8_t quantity )
{
auto itemInfo = g_exdData.getItemInfo( catalogId );
@@ -587,7 +587,7 @@ void Core::Inventory::swapItem( uint16_t fromInventoryId, uint8_t fromSlotId, ui
{
updateContainer( fromInventoryId, fromSlotId, nullptr );
fromInventoryId = getArmoryToEquipSlot( toSlot );
- fromSlotId = m_inventoryMap[fromInventoryId]->getFreeSlot();
+ fromSlotId = static_cast < uint8_t >( m_inventoryMap[fromInventoryId]->getFreeSlot() );
}
auto containerTypeFrom = getContainerType( fromInventoryId );
diff --git a/src/servers/Server_Zone/Inventory/Inventory.h b/src/servers/Server_Zone/Inventory/Inventory.h
index adc99715..63dab641 100644
--- a/src/servers/Server_Zone/Inventory/Inventory.h
+++ b/src/servers/Server_Zone/Inventory/Inventory.h
@@ -140,7 +140,7 @@ public:
InvSlotPairVec getSlotsOfItemsInInventory( uint32_t catalogId );
InvSlotPair getFreeBagSlot();
- int16_t addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint16_t quantity = 1 );
+ int16_t addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint8_t quantity = 1 );
void moveItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot );
void swapItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot );
void discardItem( uint16_t fromInventoryId, uint8_t fromSlotId );
@@ -175,7 +175,7 @@ public:
bool addCrystal( CrystalType type, uint32_t amount );
/*! remove amount from the crystals of type */
bool removeCrystal( CrystalType type, uint32_t amount );
- bool isObtainable( uint32_t catalogId, uint16_t quantity );
+ bool isObtainable( uint32_t catalogId, uint8_t quantity );
void updateCrystalDb();
diff --git a/src/servers/Server_Zone/Network/Handlers/GMCommandHandlers.cpp b/src/servers/Server_Zone/Network/Handlers/GMCommandHandlers.cpp
index 973b4bb1..36c1949a 100644
--- a/src/servers/Server_Zone/Network/Handlers/GMCommandHandlers.cpp
+++ b/src/servers/Server_Zone/Network/Handlers/GMCommandHandlers.cpp
@@ -70,6 +70,7 @@ enum GmCommand
Tp = 0x0066,
Gp = 0x0067,
Exp = 0x0068,
+ Inv = 0x006A,
Item = 0x00C8,
Gil = 0x00C9,
@@ -352,6 +353,17 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac
" was set to " + std::to_string( targetPlayer->getGcRankArray()[targetPlayer->getGc() - 1] ) );
break;
}
+ case GmCommand::Inv:
+ {
+ if( targetActor->getInvincibilityType() == Common::InvincibilityType::InvincibilityRefill )
+ targetActor->setInvincibilityType( Common::InvincibilityType::InvincibilityNone );
+ else
+ targetActor->setInvincibilityType( Common::InvincibilityType::InvincibilityRefill );
+
+ pPlayer->sendNotice( "Invincibility for " + targetPlayer->getName() +
+ " was switched." );
+ break;
+ }
default:
pPlayer->sendUrgent( "GM1 Command not implemented: " + std::to_string( commandId ) );
diff --git a/src/servers/Server_Zone/ServerZone.cpp b/src/servers/Server_Zone/ServerZone.cpp
index c7218dbb..75f72395 100644
--- a/src/servers/Server_Zone/ServerZone.cpp
+++ b/src/servers/Server_Zone/ServerZone.cpp
@@ -54,7 +54,8 @@ Core::LinkshellMgr g_linkshellMgr;
Core::Db::DbWorkerPool< Core::Db::CharaDbConnection > CharacterDatabase;
Core::ServerZone::ServerZone( const std::string& configPath, uint16_t serverId )
- : m_configPath( configPath )
+ : m_configPath( configPath ),
+ m_bRunning( true )
{
m_pConfig = XMLConfigPtr( new XMLConfig );
}
@@ -332,12 +333,8 @@ void Core::ServerZone::run( int32_t argc, char* argv[] )
g_log.setLogPath( "log\\SapphireZone_" );
g_log.init();
- g_log.info( "===========================================================" );
- g_log.info( "Sapphire Server Project " );
- g_log.info( "Version: " + Core::Version::VERSION );
- g_log.info( "GitHash: " + Core::Version::GIT_HASH );
- g_log.info( "Compiled: " __DATE__ " " __TIME__ );
- g_log.info( "===========================================================" );
+
+ printBanner();
if( !loadSettings( argc, argv ) )
{
@@ -364,24 +361,47 @@ void Core::ServerZone::run( int32_t argc, char* argv[] )
Network::HivePtr hive( new Network::Hive() );
Network::addServerToHive< Network::GameConnection >( m_ip, m_port, hive );
- g_scriptMgr.init();
-
g_log.info( "ZoneMgr: Setting up zones" );
g_zoneMgr.createZones();
+ g_scriptMgr.init();
+
std::vector< std::thread > thread_list;
- thread_list.push_back( std::thread( std::bind( &Network::Hive::Run, hive.get() ) ) );
+ thread_list.emplace_back( std::thread( std::bind( &Network::Hive::Run, hive.get() ) ) );
g_log.info( "Server listening on port: " + std::to_string( m_port ) );
g_log.info( "Ready for connections..." );
- while( true )
+ mainLoop();
+
+ for( auto& thread_entry : thread_list )
{
- std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) );
+ thread_entry.join();
+ }
+
+}
+
+void Core::ServerZone::printBanner() const
+{
+ g_log.info("===========================================================" );
+ g_log.info( "Sapphire Server Project " );
+ g_log.info( "Version: x.y.z" );
+ g_log.info( "Compiled: " __DATE__ " " __TIME__ );
+ g_log.info( "===========================================================" );
+}
+
+void Core::ServerZone::mainLoop()
+{
+ while( isRunning() )
+ {
+ this_thread::sleep_for( chrono::milliseconds( 50 ) );
g_zoneMgr.updateZones();
- std::lock_guard lock( m_sessionMutex );
- for( auto sessionIt : m_sessionMap )
+
+ auto currTime = static_cast< uint32_t >( time( nullptr ) );
+
+ lock_guard< std::mutex > lock( this->m_sessionMutex );
+ for( auto sessionIt : this->m_sessionMap )
{
auto session = sessionIt.second;
if( session && session->getPlayer() )
@@ -393,9 +413,9 @@ void Core::ServerZone::run( int32_t argc, char* argv[] )
}
}
- uint32_t currTime = static_cast< uint32_t >( time( nullptr ) );
- auto it = m_sessionMap.begin();
- for( ; it != m_sessionMap.end(); )
+
+ auto it = this->m_sessionMap.begin();
+ for( ; it != this->m_sessionMap.end(); )
{
uint32_t diff = currTime - it->second->getLastDataTime();
@@ -403,11 +423,11 @@ void Core::ServerZone::run( int32_t argc, char* argv[] )
if( diff > 20 )
{
- g_log.info( "[" + std::to_string( it->second->getId() ) + "] Session time out" );
+ g_log.info("[" + std::to_string(it->second->getId() ) + "] Session time out" );
it->second->close();
// if( it->second.unique() )
{
- it = m_sessionMap.erase( it );
+ it = this->m_sessionMap.erase(it );
}
}
else
@@ -418,13 +438,6 @@ void Core::ServerZone::run( int32_t argc, char* argv[] )
}
}
-
- // currently never reached, need a "stopServer" variable to break out of the above while loop
- /*for( auto& thread_entry : thread_list )
- {
- thread_entry.join();
- }*/
-
}
bool Core::ServerZone::createSession( uint32_t sessionId )
@@ -510,3 +523,8 @@ void Core::ServerZone::updateSession( std::string playerName )
it->second->loadPlayer();
}
+bool Core::ServerZone::isRunning() const
+{
+ return m_bRunning;
+}
+
diff --git a/src/servers/Server_Zone/ServerZone.h b/src/servers/Server_Zone/ServerZone.h
index 2472c487..73f90675 100644
--- a/src/servers/Server_Zone/ServerZone.h
+++ b/src/servers/Server_Zone/ServerZone.h
@@ -40,12 +40,20 @@ namespace Core {
Entity::BattleNpcTemplatePtr getBnpcTemplate( std::string templateName );
+ void mainLoop();
+
+ bool isRunning() const;
+
+ void printBanner() const;
+
private:
uint16_t m_port;
std::string m_ip;
+ bool m_bRunning;
+
std::string m_configPath;
XMLConfigPtr m_pConfig;
diff --git a/src/servers/Server_Zone/StatusEffect/StatusEffectContainer.cpp b/src/servers/Server_Zone/StatusEffect/StatusEffectContainer.cpp
index e842d0dc..c473aa54 100644
--- a/src/servers/Server_Zone/StatusEffect/StatusEffectContainer.cpp
+++ b/src/servers/Server_Zone/StatusEffect/StatusEffectContainer.cpp
@@ -194,13 +194,13 @@ void Core::StatusEffect::StatusEffectContainer::update()
if( thisTickDmg != 0 )
{
m_pOwner->takeDamage( thisTickDmg );
- m_pOwner->sendToInRangeSet( ActorControlPacket142( m_pOwner->getId(), HPFloatingText, 0, 3, thisTickDmg ) );
+ m_pOwner->sendToInRangeSet( ActorControlPacket142( m_pOwner->getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Damage ), thisTickDmg ) );
}
if( thisTickHeal != 0 )
{
m_pOwner->heal( thisTickDmg );
- m_pOwner->sendToInRangeSet( ActorControlPacket142( m_pOwner->getId(), HPFloatingText, 0, 4, thisTickHeal ) );
+ m_pOwner->sendToInRangeSet( ActorControlPacket142( m_pOwner->getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Heal ), thisTickHeal ) );
}
}
diff --git a/src/tools/exd_common_gen/CMakeLists.txt b/src/tools/exd_common_gen/CMakeLists.txt
new file mode 100644
index 00000000..2d5839d9
--- /dev/null
+++ b/src/tools/exd_common_gen/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 2.6)
+cmake_policy(SET CMP0015 NEW)
+project(Tool_ExdCommonGen)
+
+set(SAPPHIRE_BOOST_VER 1.63.0)
+set(SAPPHIRE_BOOST_FOLDER_NAME boost_1_63_0)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin/")
+
+
+file(GLOB SERVER_PUBLIC_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*")
+file(GLOB SERVER_SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}*.c*")
+
+#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "../bin/")
+add_executable(exd_common_gen ${SERVER_PUBLIC_INCLUDE_FILES} ${SERVER_SOURCE_FILES})
+
+set_target_properties(exd_common_gen PROPERTIES
+ CXX_STANDARD 14
+ CXX_STANDARD_REQUIRED ON
+ CXX_EXTENSIONS ON
+ RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../bin/"
+ RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../bin/"
+ RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../bin/"
+ RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../bin/"
+)
+
+if (UNIX)
+ target_link_libraries (exd_common_gen Common xivdat pthread mysqlclient dl z)
+else()
+ target_link_libraries (exd_common_gen Common xivdat libmysql zlib1)
+endif()
+
+target_link_libraries(exd_common_gen ${Boost_LIBRARIES} ${Boost_LIBRARIES})
+
diff --git a/src/tools/exd_common_gen/generated.h b/src/tools/exd_common_gen/generated.h
new file mode 100644
index 00000000..28b10c3b
--- /dev/null
+++ b/src/tools/exd_common_gen/generated.h
@@ -0,0 +1,560 @@
+[14:21:11][info] Setting up EXD data
+[14:21:12][info] /* This file has been automatically generated.
+ Changes will be lost upon regeneration.
+ To change the content edit tools/exd_common_gen */
+namespace Core {
+namespace Common {
+
+ ///////////////////////////////////////////////////////////
+ //ActionCategory.exd
+ enum ActionCategory : uint8_t
+ {
+ Autoattack = 1,
+ Spell = 2,
+ Weaponskill = 3,
+ Ability = 4,
+ Item = 5,
+ DoLAbility = 6,
+ DoHAbility = 7,
+ Event = 8,
+ LimitBreak = 9,
+ System = 10,
+ Artillery = 11,
+ Mount = 12,
+ Glamour = 13,
+ ItemManipulation = 14,
+ AdrenalineRush = 15,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //BeastReputationRank.exd
+ enum BeastReputationRank : uint8_t
+ {
+ None = 0,
+ Neutral = 1,
+ Recognized = 2,
+ Friendly = 3,
+ Trusted = 4,
+ Respected = 5,
+ Honored = 6,
+ Sworn = 7,
+ Allied = 8,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //BeastTribe.exd
+ enum BeastTribe : uint8_t
+ {
+ Amaljaa = 1,
+ Sylphs = 2,
+ Kobolds = 3,
+ Sahagin = 4,
+ Ixal = 5,
+ VanuVanu = 6,
+ Vath = 7,
+ Moogles = 8,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //ClassJob.exd
+ enum ClassJob : uint8_t
+ {
+ Adventurer = 0,
+ Gladiator = 1,
+ Pugilist = 2,
+ Marauder = 3,
+ Lancer = 4,
+ Archer = 5,
+ Conjurer = 6,
+ Thaumaturge = 7,
+ Carpenter = 8,
+ Blacksmith = 9,
+ Armorer = 10,
+ Goldsmith = 11,
+ Leatherworker = 12,
+ Weaver = 13,
+ Alchemist = 14,
+ Culinarian = 15,
+ Miner = 16,
+ Botanist = 17,
+ Fisher = 18,
+ Paladin = 19,
+ Monk = 20,
+ Warrior = 21,
+ Dragoon = 22,
+ Bard = 23,
+ Whitemage = 24,
+ Blackmage = 25,
+ Arcanist = 26,
+ Summoner = 27,
+ Scholar = 28,
+ Rogue = 29,
+ Ninja = 30,
+ Machinist = 31,
+ Darkknight = 32,
+ Astrologian = 33,
+ Samurai = 34,
+ Redmage = 35,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //ContentType.exd
+ enum ContentType : uint8_t
+ {
+ DutyRoulette = 1,
+ Dungeons = 2,
+ Guildhests = 3,
+ Trials = 4,
+ Raids = 5,
+ PvP = 6,
+ QuestBattles = 7,
+ FATEs = 8,
+ TreasureHunt = 9,
+ Levequests = 10,
+ GrandCompany = 11,
+ Companions = 12,
+ BeastTribeQuests = 13,
+ OverallCompletion = 14,
+ PlayerCommendation = 15,
+ DisciplesoftheLand = 16,
+ DisciplesoftheHand = 17,
+ RetainerVentures = 18,
+ GoldSaucer = 19,
+ DeepDungeons = 21,
+ WondrousTails = 24,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //EmoteCategory.exd
+ enum EmoteCategory : uint8_t
+ {
+ General = 1,
+ Persistent = 2,
+ Expressions = 3,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //ExVersion.exd
+ enum ExVersion : uint8_t
+ {
+ ARealmReborn = 0,
+ Heavensward = 1,
+ Stormblood = 2,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //GrandCompany.exd
+ enum GrandCompany : uint8_t
+ {
+ None = 0,
+ Maelstrom = 1,
+ OrderoftheTwinAdder = 2,
+ ImmortalFlames = 3,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //GuardianDeity.exd
+ enum GuardianDeity : uint8_t
+ {
+ HalonetheFury = 1,
+ MenphinatheLover = 2,
+ ThaliaktheScholar = 3,
+ NymeiatheSpinner = 4,
+ LlymlaentheNavigator = 5,
+ OschontheWanderer = 6,
+ ByregottheBuilder = 7,
+ RhalgrtheDestroyer = 8,
+ AzeymatheWarden = 9,
+ NaldthaltheTraders = 10,
+ NophicatheMatron = 11,
+ AlthyktheKeeper = 12,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //ItemUICategory.exd
+ enum ItemUICategory : uint8_t
+ {
+ PugilistsArm = 1,
+ GladiatorsArm = 2,
+ MaraudersArm = 3,
+ ArchersArm = 4,
+ LancersArm = 5,
+ OnehandedThaumaturgesArm = 6,
+ TwohandedThaumaturgesArm = 7,
+ OnehandedConjurersArm = 8,
+ TwohandedConjurersArm = 9,
+ ArcanistsGrimoire = 10,
+ Shield = 11,
+ CarpentersPrimaryTool = 12,
+ CarpentersSecondaryTool = 13,
+ BlacksmithsPrimaryTool = 14,
+ BlacksmithsSecondaryTool = 15,
+ ArmorersPrimaryTool = 16,
+ ArmorersSecondaryTool = 17,
+ GoldsmithsPrimaryTool = 18,
+ GoldsmithsSecondaryTool = 19,
+ LeatherworkersPrimaryTool = 20,
+ LeatherworkersSecondaryTool = 21,
+ WeaversPrimaryTool = 22,
+ WeaversSecondaryTool = 23,
+ AlchemistsPrimaryTool = 24,
+ AlchemistsSecondaryTool = 25,
+ CulinariansPrimaryTool = 26,
+ CulinariansSecondaryTool = 27,
+ MinersPrimaryTool = 28,
+ MinersSecondaryTool = 29,
+ BotanistsPrimaryTool = 30,
+ BotanistsSecondaryTool = 31,
+ FishersPrimaryTool = 32,
+ FishingTackle = 33,
+ Head = 34,
+ Body = 35,
+ Legs = 36,
+ Hands = 37,
+ Feet = 38,
+ Waist = 39,
+ Necklace = 40,
+ Earrings = 41,
+ Bracelets = 42,
+ Ring = 43,
+ Medicine = 44,
+ Ingredient = 45,
+ Meal = 46,
+ Seafood = 47,
+ Stone = 48,
+ Metal = 49,
+ Lumber = 50,
+ Cloth = 51,
+ Leather = 52,
+ Bone = 53,
+ Reagent = 54,
+ Dye = 55,
+ Part = 56,
+ Furnishing = 57,
+ Materia = 58,
+ Crystal = 59,
+ Catalyst = 60,
+ Miscellany = 61,
+ SoulCrystal = 62,
+ Other = 63,
+ ConstructionPermit = 64,
+ Roof = 65,
+ ExteriorWall = 66,
+ Window = 67,
+ Door = 68,
+ RoofDecoration = 69,
+ ExteriorWallDecoration = 70,
+ Placard = 71,
+ Fence = 72,
+ InteriorWall = 73,
+ Flooring = 74,
+ CeilingLight = 75,
+ OutdoorFurnishing = 76,
+ Table = 77,
+ Tabletop = 78,
+ Wallmounted = 79,
+ Rug = 80,
+ Minion = 81,
+ Gardening = 82,
+ Demimateria = 83,
+ RoguesArm = 84,
+ SeasonalMiscellany = 85,
+ TripleTriadCard = 86,
+ DarkKnightsArm = 87,
+ MachinistsArm = 88,
+ AstrologiansArm = 89,
+ AirshipHull = 90,
+ AirshipRigging = 91,
+ AirshipAftcastle = 92,
+ AirshipForecastle = 93,
+ OrchestrionRoll = 94,
+ Painting = 95,
+ SamuraisArm = 96,
+ RedMagesArm = 97,
+ ScholarsArm = 98,
+ FishersSecondaryTool = 99,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //ItemSearchCategory.exd
+ enum ItemSearchCategory : uint8_t
+ {
+ PrimaryArms = 1,
+ PrimaryTools = 2,
+ PrimaryTools1 = 3,
+ Armor = 4,
+ Accessories = 5,
+ Medicines = 6,
+ Materials = 7,
+ Other = 8,
+ PugilistsArms = 9,
+ GladiatorsArms = 10,
+ MaraudersArms = 11,
+ ArchersArms = 12,
+ LancersArms = 13,
+ ThaumaturgesArms = 14,
+ ConjurersArms = 15,
+ ArcanistsArms = 16,
+ Shields = 17,
+ ThrowingWeapons = 18,
+ CarpentersTools = 19,
+ BlacksmithsTools = 20,
+ ArmorersTools = 21,
+ GoldsmithsTools = 22,
+ LeatherworkersTools = 23,
+ WeaversTools = 24,
+ AlchemistsTools = 25,
+ CulinariansTools = 26,
+ MinersTools = 27,
+ BotanistsTools = 28,
+ FishersTools = 29,
+ FishingTackle = 30,
+ Head = 31,
+ Undershirts = 32,
+ Body = 33,
+ Undergarments = 34,
+ Legs = 35,
+ Hands = 36,
+ Feet = 37,
+ Waist = 38,
+ Necklaces = 39,
+ Earrings = 40,
+ Bracelets = 41,
+ Rings = 42,
+ Medicine = 43,
+ Ingredients = 44,
+ Meals = 45,
+ Seafood = 46,
+ Stone = 47,
+ Metal = 48,
+ Lumber = 49,
+ Cloth = 50,
+ Leather = 51,
+ Bone = 52,
+ Reagents = 53,
+ Dyes = 54,
+ WeaponParts = 55,
+ Furnishings = 56,
+ Materia = 57,
+ Crystals = 58,
+ Catalysts = 59,
+ Miscellany = 60,
+ SoulCrystals = 61,
+ Arrows = 62,
+ QuestItems = 63,
+ Other1 = 64,
+ ExteriorFixtures = 65,
+ InteriorFixtures = 66,
+ OutdoorFurnishings = 67,
+ ChairsandBeds = 68,
+ Tables = 69,
+ Tabletop = 70,
+ Wallmounted = 71,
+ Rugs = 72,
+ RoguesArms = 73,
+ SeasonalMiscellany = 74,
+ Minions = 75,
+ DarkKnightsArms = 76,
+ MachinistsArms = 77,
+ AstrologiansArms = 78,
+ AirshipComponents = 79,
+ OrchestrionComponents = 80,
+ GardeningItems = 81,
+ Paintings = 82,
+ SamuraisArms = 83,
+ RedMagesArms = 84,
+ ScholarsArms = 85,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //OnlineStatus.exd
+ enum OnlineStatus : uint8_t
+ {
+ Producer = 1,
+ GameMaster = 2,
+ GameMaster1 = 3,
+ GameMaster2 = 4,
+ Disconnected = 5,
+ WaitingforFriendListApproval = 6,
+ WaitingforLinkshellApproval = 7,
+ WaitingforFreeCompanyApproval = 8,
+ NotFound = 9,
+ Offline = 10,
+ Mentor = 11,
+ Busy = 12,
+ PvP = 13,
+ PlayingTripleTriad = 14,
+ ViewingCutscene = 15,
+ UsingaChocoboPorter = 16,
+ AwayfromKeyboard = 17,
+ CameraMode = 18,
+ LookingforRepairs = 19,
+ LookingtoRepair = 20,
+ LookingtoMeldMateria = 21,
+ Roleplaying = 22,
+ LookingforParty = 23,
+ SwordforHire = 24,
+ WaitingforDutyFinder = 25,
+ RecruitingPartyMembers = 26,
+ Mentor1 = 27,
+ PvEMentor = 28,
+ TradeMentor = 29,
+ PvPMentor = 30,
+ Returner = 31,
+ NewAdventurer = 32,
+ AllianceLeader = 33,
+ AlliancePartyLeader = 34,
+ AlliancePartyMember = 35,
+ PartyLeader = 36,
+ PartyMember = 37,
+ PartyLeaderCrossworld = 38,
+ PartyMemberCrossworld = 39,
+ AnotherWorld = 40,
+ SharingDuty = 41,
+ SimilarDuty = 42,
+ InDuty = 43,
+ TrialAdventurer = 44,
+ FreeCompany = 45,
+ GrandCompany = 46,
+ Online = 47,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //Race.exd
+ enum Race : uint8_t
+ {
+ Hyur = 1,
+ Elezen = 2,
+ Lalafell = 3,
+ Miqote = 4,
+ Roegadyn = 5,
+ AuRa = 6,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //Tribe.exd
+ enum Tribe : uint8_t
+ {
+ Midlander = 1,
+ Highlander = 2,
+ Wildwood = 3,
+ Duskwight = 4,
+ Plainsfolk = 5,
+ Dunesfolk = 6,
+ SeekeroftheSun = 7,
+ KeeperoftheMoon = 8,
+ SeaWolf = 9,
+ Hellsguard = 10,
+ Raen = 11,
+ Xaela = 12,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //Town.exd
+ enum Town : uint8_t
+ {
+ Nowheresville = 0,
+ LimsaLominsa = 1,
+ Gridania = 2,
+ Uldah = 3,
+ Ishgard = 4,
+ Kugane = 7,
+ };
+
+ ///////////////////////////////////////////////////////////
+ //Weather.exd
+ enum Weather : uint8_t
+ {
+ ClearSkies = 1,
+ FairSkies = 2,
+ Clouds = 3,
+ Fog = 4,
+ Wind = 5,
+ Gales = 6,
+ Rain = 7,
+ Showers = 8,
+ Thunder = 9,
+ Thunderstorms = 10,
+ DustStorms = 11,
+ Sandstorms = 12,
+ HotSpells = 13,
+ HeatWaves = 14,
+ Snow = 15,
+ Blizzards = 16,
+ Gloom = 17,
+ Auroras = 18,
+ Darkness = 19,
+ Tension = 20,
+ Clouds1 = 21,
+ StormClouds = 22,
+ RoughSeas = 23,
+ RoughSeas1 = 24,
+ Louring = 25,
+ HeatWaves1 = 26,
+ Gloom1 = 27,
+ Gales1 = 28,
+ Eruptions = 29,
+ FairSkies1 = 30,
+ FairSkies2 = 31,
+ FairSkies3 = 32,
+ FairSkies4 = 33,
+ FairSkies5 = 34,
+ Irradiance = 35,
+ CoreRadiation = 36,
+ CoreRadiation1 = 37,
+ CoreRadiation2 = 38,
+ CoreRadiation3 = 39,
+ ShelfClouds = 40,
+ ShelfClouds1 = 41,
+ ShelfClouds2 = 42,
+ ShelfClouds3 = 43,
+ Oppression = 44,
+ Oppression1 = 45,
+ Oppression2 = 46,
+ Oppression3 = 47,
+ Oppression4 = 48,
+ UmbralWind = 49,
+ UmbralStatic = 50,
+ Smoke = 51,
+ FairSkies6 = 52,
+ RoyalLevin = 53,
+ Hyperelectricity = 54,
+ RoyalLevin1 = 55,
+ Oppression5 = 56,
+ Thunder1 = 57,
+ Thunder2 = 58,
+ CutScene = 59,
+ Multiplicity = 60,
+ Multiplicity1 = 61,
+ Rain1 = 62,
+ FairSkies7 = 63,
+ Rain2 = 64,
+ FairSkies8 = 65,
+ Dragonstorm = 66,
+ Dragonstorm1 = 67,
+ Subterrain = 68,
+ Concordance = 69,
+ Concordance1 = 70,
+ BeyondTime = 71,
+ BeyondTime1 = 72,
+ BeyondTime2 = 73,
+ DemonicInfinity = 74,
+ DemonicInfinity1 = 75,
+ DemonicInfinity2 = 76,
+ DimensionalDisruption = 77,
+ DimensionalDisruption1 = 78,
+ DimensionalDisruption2 = 79,
+ Revelstorm = 80,
+ Revelstorm1 = 81,
+ EternalBliss = 82,
+ EternalBliss1 = 83,
+ Wyrmstorm = 84,
+ Wyrmstorm1 = 85,
+ Revelstorm2 = 86,
+ Quicklevin = 87,
+ Thunder3 = 88,
+ DimensionalDisruption3 = 89,
+ };
+}
+}
+
diff --git a/src/tools/exd_common_gen/main.cpp b/src/tools/exd_common_gen/main.cpp
new file mode 100644
index 00000000..5279e5d2
--- /dev/null
+++ b/src/tools/exd_common_gen/main.cpp
@@ -0,0 +1,114 @@
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+
+Core::Logger g_log;
+Core::Data::ExdData g_exdData;
+
+
+//const std::string datLocation( "/opt/sapphire_3_15_0/bin/sqpack" );
+const std::string datLocation( "C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv" );
+
+std::string generateEnum( const std::string& exd, int8_t nameIndex, const std::string& type, bool useLang = true )
+{
+
+ xiv::dat::GameData data( datLocation );
+ xiv::exd::ExdData eData( data );
+
+ std::map< std::string, uint32_t> nameMap;
+
+ std::string result = "\n ///////////////////////////////////////////////////////////\n";
+ result += " //" + exd + ".exd\n";
+ result += " enum " + exd + " : " + type + "\n";
+ result += " {\n";
+ auto lang = useLang ? xiv::exd::Language::en : xiv::exd::Language::none;
+ auto access = g_exdData.setupDatAccess( exd, lang );
+ auto rows = access.get_rows();
+
+ for( auto row : rows )
+ {
+ auto& fields = row.second;
+ uint32_t id = row.first;
+ auto test = boost::get< std::string >( &fields.at( nameIndex ) );
+ if( !test )
+ continue;
+ auto str = *test ;
+ str.erase( boost::remove_if( str, boost::is_any_of(",_-':!(){} \x02\x1f\x01\x03") ), str.end() );
+ if( str.empty() )
+ continue;
+ str[0] = std::toupper( str[0] );
+
+ auto it = nameMap.find( str );
+ if( it != nameMap.end() )
+ {
+ nameMap[str]++;
+ str = str + std::to_string( nameMap[str] );
+ }
+ else
+ {
+ nameMap[str] = 0;
+ }
+
+ result += " " + str + " = " + std::to_string( id ) + ",\n";
+
+ }
+ result += " };\n";
+
+ return result;
+
+}
+
+int main()
+{
+
+ g_log.init();
+
+
+ g_log.info( "Setting up EXD data" );
+ if( !g_exdData.init( datLocation ) )
+ {
+ g_log.fatal( "Error setting up EXD data " );
+ return 0;
+ }
+
+ std::string result =
+ "/* This file has been automatically generated.\n Changes will be lost upon regeneration.\n To change the content edit tools/exd_common_gen */\n";
+
+
+ result += "namespace Core {\n";
+ result += "namespace Common {\n";
+ result += generateEnum( "ActionCategory", 0, "uint8_t" );
+ result += generateEnum( "BeastReputationRank", 1, "uint8_t" );
+ result += generateEnum( "BeastTribe", 10, "uint8_t" );
+ result += generateEnum( "ClassJob", 0, "uint8_t" );
+ result += generateEnum( "ContentType", 0, "uint8_t" );
+ result += generateEnum( "EmoteCategory", 0, "uint8_t" );
+ result += generateEnum( "ExVersion", 0, "uint8_t" );
+ result += generateEnum( "GrandCompany", 0, "uint8_t" );
+ result += generateEnum( "GuardianDeity", 0, "uint8_t" );
+ result += generateEnum( "ItemUICategory", 0, "uint8_t" );
+ result += generateEnum( "ItemSearchCategory", 0, "uint8_t" );
+ result += generateEnum( "OnlineStatus", 2, "uint8_t" );
+ result += generateEnum( "Race", 1, "uint8_t" );
+ result += generateEnum( "Tribe", 0, "uint8_t" );
+ result += generateEnum( "Town", 0, "uint8_t" );
+ result += generateEnum( "Weather", 1, "uint8_t" );
+ result += "}\n";
+ result += "}\n";
+ g_log.info( result );
+ return 0;
+}
diff --git a/src/tools/quest_parser/CMakeLists.txt b/src/tools/quest_parser/CMakeLists.txt
index 1a314ae9..5fd8176d 100644
--- a/src/tools/quest_parser/CMakeLists.txt
+++ b/src/tools/quest_parser/CMakeLists.txt
@@ -15,58 +15,6 @@ include_directories("../")
file(GLOB SERVER_PUBLIC_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*")
file(GLOB SERVER_SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}*.c*")
-set(SERVER_COMMON_DIR ../../sapphire/Server_Common)
-set(Boost_USE_STATIC_LIBS ON)
-
-if(UNIX)
- include_directories("/usr/include/mysql/")
- message(STATUS "Setting GCC flags")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -m32")
-
- find_package(Boost ${SAPPHIRE_BOOST_VER} COMPONENTS log log_setup thread date_time filesystem system)
- if(Boost_FOUND)
- set(BOOST_LIBRARY_DIR ${Boost_LIBRARY_DIR})
- else()
- if (EXISTS /opt/build_libs/${SAPPHIRE_BOOST_FOLDER_NAME})
- set(Boost_INCLUDE_DIR /opt/build_libs/${SAPPHIRE_BOOST_FOLDER_NAME})
- set(BOOST_LIBRARYDIR /opt/build_libs/${SAPPHIRE_BOOST_FOLDER_NAME}/stage/lib)
- find_package(Boost ${SAPPHIRE_BOOST_VER} COMPONENTS log log_setup thread date_time filesystem system)
- else()
- message(FATAL_ERROR "Unable to find boost ${SAPPHIRE_BOOST_VER} package!")
- endif()
- endif()
-else()
- add_definitions(-D_WIN32_WINNT=0x601)
- add_definitions(-D_CRT_SECURE_NO_WARNINGS)
- include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/MySQL/")
- message(STATUS "Setting MSVC flags")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHc")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
-
- if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../../lib/${SAPPHIRE_BOOST_FOLDER_NAME})
- message(STATUS "Using boost in /src/lib")
- set(Boost_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../lib/${SAPPHIRE_BOOST_FOLDER_NAME})
- set(BOOST_LIBRARYDIR ${CMAKE_CURRENT_SOURCE_DIR}/../../lib/${SAPPHIRE_BOOST_FOLDER_NAME}/lib32-msvc-14.0)
- else()
- find_package(Boost ${SAPPHIRE_BOOST_VER} COMPONENTS log log_setup thread date_time filesystem system)
- if(Boost_FOUND)
- set(BOOST_LIBRARY_DIR ${Boost_LIBRARY_DIR})
- elseif ((EXISTS $ENV{BOOST_ROOT_DIR}) AND (EXISTS $ENV{BOOST_LIB_DIR}))
- set(Boost_INCLUDE_DIR $ENV{BOOST_ROOT_DIR})
- set(BOOST_LIBRARYDIR $ENV{BOOST_LIB_DIR})
- else()
- message(FATAL_ERROR "SapphireError: Unable to find boost ${SAPPHIRE_BOOST_VER} package and environment variables BOOST_ROOT_DIR and BOOST_LIB_DIR not set!")
- endif()
- endif()
-endif()
-
-include_directories(${Boost_INCLUDE_DIR})
-
-link_directories(${BOOST_LIBRARYDIR})
-link_directories(${SERVER_COMMON_DIR})
-link_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../sapphire/datReader/)
-link_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../lib/MySQL)
-link_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../lib/zlib)
#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "../bin/")
add_executable(quest_parse ${SERVER_PUBLIC_INCLUDE_FILES} ${SERVER_SOURCE_FILES})
diff --git a/src/tools/quest_parser/main.cpp b/src/tools/quest_parser/main.cpp
index d1ac6ca1..f4ec46b1 100644
--- a/src/tools/quest_parser/main.cpp
+++ b/src/tools/quest_parser/main.cpp
@@ -12,7 +12,6 @@
#include
-#include
Core::Logger g_log;
Core::Data::ExdData g_exdData;