diff --git a/bin/web/assets/img/background.png b/bin/web/assets/img/background.png index a2fae17b..ea97ac81 100644 Binary files a/bin/web/assets/img/background.png and b/bin/web/assets/img/background.png differ diff --git a/scripts/chai/CmnDef/CmnDefCutSceneReplay.chai b/scripts/chai/CmnDef/CmnDefCutSceneReplay.chai new file mode 100644 index 00000000..6f390751 --- /dev/null +++ b/scripts/chai/CmnDef/CmnDefCutSceneReplay.chai @@ -0,0 +1,38 @@ + +class CmnDefCutSceneReplayDef +{ + + def CmnDefCutSceneReplayDef() + { + this.id = 721028; + } + + def Scene00000( player ) + { + player.eventPlay( this.id, 0, 0x2000/*flags*/, 0/*unk*/, 1/*unk*/, + fun( player, eventId, param1, param2, param3 ) + { + if( param2 != 0 ) + { + CmnDefCutSceneReplay.Scene00001( player, param2 ); + } + }); + } + + def Scene00001( player, returnScene ) + { + player.eventPlay( this.id, 1, 0xFB2EC8F8/*flags*/, 0/*unk*/, 1, returnScene, + fun( player, eventId, param1, param2, param3 ) + { + + }); + } + + def onTalk( eventId, player, actorId ) + { + this.Scene00000( player ); + } + +}; + +GLOBAL CmnDefCutSceneReplay = CmnDefCutSceneReplayDef(); \ No newline at end of file diff --git a/scripts/chai/CmnDef/CmnDefInnBed.chai b/scripts/chai/CmnDef/CmnDefInnBed.chai new file mode 100644 index 00000000..4ea1ba9c --- /dev/null +++ b/scripts/chai/CmnDef/CmnDefInnBed.chai @@ -0,0 +1,62 @@ + +class CmnDefInnBedDef +{ + + def CmnDefInnBedDef() + { + this.id = 720916; + } + + def Scene00000( player ) //Menu + { + player.eventPlay( this.id, 0, 0x2000/*flags*/, 0/*unk*/, 1/*unk*/, + fun( player, eventId, param1, param2, param3 ) + { + if( param2 > 1 ) + { + CmnDefInnBed.Scene00001( player, param2 ); + } + + }); + } + + def Scene00001( player, what ) //Lay down + { + player.eventPlay( this.id, 1, 0xF32E48F8/*flags*/, 0/*unk*/, 1/*unk*/, what, + fun( player, eventId, param1, param2, param3 ) + { + CmnDefInnBed.Scene00002( player, param2 ); + }); + } + + def Scene00002( player, what ) //Log out + { + player.eventPlay( this.id, 2, 0xF32E48F8/*flags*/, 0/*unk*/, 1/*unk*/, what, + fun( player, eventId, param1, param2, param3 ) + { + + }); + } + + def Scene00100( player ) //Wake up + { + player.eventPlay( this.id, 100, 0xF32E48F8/*flags*/, 0/*unk*/, 0/*unk*/, + fun( player, eventId, param1, param2, param3 ) + { + + }); + } + + def onTalk( eventId, player, actorId ) + { + this.Scene00000( player ); + } + + def onEnterTerritory( eventId, player, param1, param2 ) + { + this.Scene00100( player ); + } + +}; + +GLOBAL CmnDefInnBed = CmnDefInnBedDef(); \ No newline at end of file diff --git a/scripts/chai/CmnDef/HouFurOrchestrion.chai b/scripts/chai/CmnDef/HouFurOrchestrion.chai new file mode 100644 index 00000000..adc60f55 --- /dev/null +++ b/scripts/chai/CmnDef/HouFurOrchestrion.chai @@ -0,0 +1,26 @@ + +class HouFurOrchestrionDef +{ + + def HouFurOrchestrionDef() + { + this.id = 721226; + } + + def Scene00000( player ) + { + player.eventPlay( this.id, 0, 0x2000/*flags*/, 0/*unk*/, 1/*unk*/, + fun( player, eventId, param1, param2, param3 ) + { + + }); + } + + def onTalk( eventId, player, actorId ) + { + this.Scene00000( player ); + } + +}; + +GLOBAL HouFurOrchestrion = HouFurOrchestrionDef(); \ No newline at end of file diff --git a/sql/charadetail.sql b/sql/charadetail.sql new file mode 100644 index 00000000..8716365d --- /dev/null +++ b/sql/charadetail.sql @@ -0,0 +1,90 @@ +-- -------------------------------------------------------- +-- Host: 127.0.0.1 +-- Server version: 10.1.24-MariaDB - mariadb.org binary distribution +-- Server OS: Win32 +-- HeidiSQL Version: 9.4.0.5125 +-- -------------------------------------------------------- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8mb4 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + +-- Dumping structure for table sapphire.charadetail +CREATE TABLE IF NOT EXISTS `charadetail` ( + `GuardianDeity` int(3) DEFAULT NULL, + `BirthDay` int(3) DEFAULT NULL, + `BirthMonth` int(3) NOT NULL, + `Class` int(3) DEFAULT NULL, + `MakeValid` int(3) DEFAULT NULL, + `RetainerId` int(20) DEFAULT NULL, + `RetainerName` varchar(32) DEFAULT NULL, + `CreateUnixTime` int(20) DEFAULT NULL, + `IsActive` int(3) DEFAULT NULL, + `IsRename` int(3) DEFAULT NULL, + `Status` int(3) DEFAULT NULL, + `Platform` varchar(32) DEFAULT NULL, + `TotalPlayTime` int(10) DEFAULT '0', + `TotalPlayTimeSecond` float DEFAULT NULL, + `FirstClass` int(3) DEFAULT NULL, + `HomePoint` int(3) DEFAULT NULL, + `FavoritePoint` binary(3) DEFAULT NULL, + `RestPoint` int(10) DEFAULT NULL, + `RentalTimer` float DEFAULT NULL, + `StartTown` int(3) DEFAULT NULL, + `ActiveTitle` int(5) DEFAULT NULL, + `TitleList` binary(32) DEFAULT NULL, + `Achievement` binary(16) DEFAULT NULL, + `Aetheryte` binary(16) DEFAULT NULL, + `HowTo` binary(33) DEFAULT NULL, + `Minions` binary(33) DEFAULT NULL, + `Mounts` binary(13) DEFAULT NULL, + `EquippedMannequin` int(5) DEFAULT NULL, + `ConfigFlags` smallint(5) NOT NULL DEFAULT '0', + `GatheringHistoryPointId` binary(8) DEFAULT NULL, + `GatheringDivisionOpenFla` binary(40) DEFAULT NULL, + `GatheringItemGetFlags` binary(60) DEFAULT NULL, + `RecipeDivisionOpenFlags` binary(80) DEFAULT NULL, + `RecipeCreateFlags` binary(100) DEFAULT NULL, + `QuestCompleteFlags` binary(200) DEFAULT NULL, + `LeveCompleteFlags` binary(200) DEFAULT NULL, + `OpeningSequence` int(3) DEFAULT '0', + `QuestTracking` binary(10) DEFAULT NULL, + `LeveTicketNum` int(3) DEFAULT NULL, + `LeveTicketLastGetTime` int(10) DEFAULT NULL, + `GuildleveAssignmentSeed` int(5) DEFAULT NULL, + `GuildleveAssignmentCount` int(3) DEFAULT NULL, + `GuildleveFactionCreditBr` int(5) DEFAULT NULL, + `GuildleveFactionCreditAz` int(5) DEFAULT NULL, + `GuildleveFactionCreditHo` int(5) DEFAULT NULL, + `GrandCompany` int(3) DEFAULT NULL, + `GrandCompanyRank` binary(3) DEFAULT NULL, + `Discovery` blob, + `ContentRetryTime` blob, + `ContentJoinTime` int(10) DEFAULT NULL, + `ContentClearFlag` blob, + `CFPenaltyUntil` int(10) unsigned NOT NULL DEFAULT '0', + `TownWarpFstFlags` binary(2) DEFAULT NULL, + `PathId` int(10) DEFAULT NULL, + `StepIndex` int(5) DEFAULT NULL, + `ChocoboTaxiStandFlags` binary(8) DEFAULT NULL, + `GMRank` int(3) DEFAULT '0', + `EquipDisplayFlags` int(3) DEFAULT '0', + `unlocks` binary(64) DEFAULT NULL, + `Orchestrion` binary(38) DEFAULT NULL, + `CharacterId` int(20) NOT NULL DEFAULT '0', + `IS_DELETE` int(3) DEFAULT '0', + `IS_NOT_ACTIVE_FLG` int(3) DEFAULT '0', + `UPDATE_DATE` datetime DEFAULT NULL, + PRIMARY KEY (`CharacterId`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- Dumping data for table sapphire.charadetail: 0 rows +DELETE FROM `charadetail`; +/*!40000 ALTER TABLE `charadetail` DISABLE KEYS */; +/*!40000 ALTER TABLE `charadetail` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; diff --git a/sql/update.sql b/sql/update.sql index 539ee4e1..e9fb826a 100644 --- a/sql/update.sql +++ b/sql/update.sql @@ -15,4 +15,11 @@ -- ADD `Lv_25` INT(5) NOT NULL DEFAULT '0' AFTER `Exp_24`, -- ADD `Exp_25` INT(19) NOT NULL DEFAULT '0' AFTER `Lv_25`; -- ------------------------------------------- --- update.sql Before Merge into Other SQL's 30/08/2017 \ No newline at end of file +-- update.sql Before Merge into Other SQL's 30/08/2017 +-- ------------------------------------------- +-- ALTER TABLE `charadetail` ADD `EquipDisplayFlags` int(3) DEFAULT '0' AFTER `GMRank`; +-- ------------------------------------------- +-- update.sql before titles added 09/10/2017 + +ALTER TABLE `charadetail` CHANGE `TitleList` `Titlelist` BINARY(48) NULL DEFAULT NULL; +ALTER TABLE `charadetail` ADD COLUMN `Orchestrion` BINARY(38) DEFAULT NULL AFTER `unlocks`; \ No newline at end of file diff --git a/src/servers/Server_Common/Common.h b/src/servers/Server_Common/Common.h index 9682b6e8..f608e8bc 100644 --- a/src/servers/Server_Common/Common.h +++ b/src/servers/Server_Common/Common.h @@ -917,9 +917,11 @@ namespace Core { SetMaxGearSets = 0x230, - ToggleDisplayHeadAndWeapon = 0x260, + SetCharaGearParamUI = 0x260, - GearSetEquipMsg = 0x321 + GearSetEquipMsg = 0x321, + + ToggleOrchestrionUnlock = 0x396 }; enum struct ChatType : uint32_t @@ -1027,6 +1029,15 @@ namespace Core { Unused100 }; + enum EquipDisplayFlags : uint8_t + { + HideNothing = 0x0, + HideHead = 0x1, + HideWeapon = 0x2, + + Visor = 0x40, + }; + struct ServerEntry { uint32_t serverId; diff --git a/src/servers/Server_Common/Exd/ExdData.cpp b/src/servers/Server_Common/Exd/ExdData.cpp index 40e6e28d..f7822502 100644 --- a/src/servers/Server_Common/Exd/ExdData.cpp +++ b/src/servers/Server_Common/Exd/ExdData.cpp @@ -85,7 +85,7 @@ bool Core::Data::ExdData::loadZoneInfo() int16_t map_index = getField< int16_t >( mapDataFields, 12 ); bool is_two_bytes = getField< bool >( mapDataFields, 15 ); - uint8_t weather_rate = getField< uint8_t >( fields, 10 ) > 75 ? 0 : getField< uint8_t >( fields, 10 ); + uint16_t weather_rate = getField< uint16_t >( fields, 10 ) > 75 ? 0 : getField< uint16_t >( fields, 10 ); auto weatherRateFields = weatherRate.get_row( weather_rate ); int32_t aetheryte_index = getField< int32_t >( fields, 20 ); @@ -136,6 +136,16 @@ bool Core::Data::ExdData::loadStatusEffectInfo() StatusEffectInfo info { 0 }; info.id = id; info.name = getField< std::string >( fields, 0 ); + info.lock_movement = getField< bool >( fields, 7 ); // 7 + info.lock_actions = getField< bool >( fields, 9 ); // 9 + info.lock_control = getField< bool >( fields, 10 ); // 10 + info.transfiguration = getField< bool >( fields, 11 ); // 11 + info.can_dispel = getField< bool >( fields, 13 ); // 13 + info.is_permanent = getField< bool >( fields, 15 ); // 15 + info.inflicted_by_actor = getField< bool >( fields, 17 ); // 17 + info.is_fc_buff = getField< bool >( fields, 21 ); // 21 + info.invisibility = getField< bool >( fields, 22 ); // 22 + m_statusEffectInfoMap[id] = info; } @@ -355,6 +365,9 @@ bool Core::Data::ExdData::loadActionInfo() uint16_t toggle_status_id = getField< uint16_t >( fields, 42 ); // 42 bool affects_position = getField< bool >( fields, 47 ); // 47 + bool no_effect_in_battle = getField< bool >( fields, 60 ); // 60 + + info->id = id; info->name = name; info->category = category; @@ -389,6 +402,8 @@ bool Core::Data::ExdData::loadActionInfo() info->toggle_status_id = toggle_status_id; info->affects_position = affects_position; + info->no_effect_in_battle = no_effect_in_battle; + // 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 ); @@ -520,26 +535,26 @@ boost::shared_ptr< Core::Data::QuestInfo > info->quest_level = getField< uint16_t >( row, 4 ); - info->enpc_resident_start = getField< uint32_t >( row, 38 ); - info->enpc_resident_end = getField< uint32_t >( row, 40 ); + info->enpc_resident_start = getField< uint32_t >( row, 40 ); + info->enpc_resident_end = getField< uint32_t >( row, 42 ); - info->reward_exp_factor = getField< uint16_t >( row, 1437 ); - info->reward_gil = getField< uint32_t >( row, 1438 ); - info->reward_gc_seals = getField< uint16_t >( row, 1440 ); + info->reward_exp_factor = getField< uint16_t >( row, 1439 ); + info->reward_gil = getField< uint32_t >( row, 1440 ); + info->reward_gc_seals = getField< uint16_t >( row, 1442 ); - info->reward_item_type = getField< uint8_t >( row, 1447 ); + info->reward_item_type = getField< uint8_t >( row, 1449 ); for( uint32_t i = 0; i < 6; i++ ) { - uint32_t entry = getField< uint32_t >( row, i + 1448 ); + uint32_t entry = getField< uint32_t >( row, i + 1450 ); if( entry > 0 ) info->reward_item.push_back( entry ); - uint8_t entry1 = getField< uint8_t >( row, i + 1455 ); + uint8_t entry1 = getField< uint8_t >( row, i + 1457 ); if( entry1 > 0 ) info->reward_item_count.push_back( entry1 ); - uint8_t entry2 = getField< uint8_t >( row, i + 1462 ); + uint8_t entry2 = getField< uint8_t >( row, i + 1464 ); if( entry2 > 0 ) info->reward_item_stain.push_back( entry2 ); @@ -547,39 +562,39 @@ boost::shared_ptr< Core::Data::QuestInfo > for( uint32_t i = 0; i < 5; i++ ) { - uint32_t entry = getField< uint32_t >( row, i + 1469 ); + uint32_t entry = getField< uint32_t >( row, i + 1471 ); if( entry > 0 ) info->reward_item_optional.push_back( entry ); - uint8_t entry1 = getField< uint8_t >( row, i + 1474 ); + uint8_t entry1 = getField< uint8_t >( row, i + 1476 ); if( entry1 > 0 ) info->reward_item_optional_count.push_back( entry1 ); - uint8_t entry2 = getField< uint8_t >( row, i + 1484 ); + uint8_t entry2 = getField< uint8_t >( row, i + 1486 ); if( entry2 > 0 ) info->reward_item_optional_stain.push_back( entry2 ); } - info->reward_emote = getField< uint8_t >( row, 1489 ); - info->reward_action = getField< uint16_t >( row, 1490 ); - info->reward_action_general1 = getField< uint8_t >( row, 1491 ); - info->reward_action_general2 = getField< uint8_t >( row, 1492 ); - info->reward_other = getField< uint8_t >( row, 1494 ); + info->reward_emote = getField< uint8_t >( row, 1491 ); + info->reward_action = getField< uint16_t >( row, 1492 ); + info->reward_action_general1 = getField< uint8_t >( row, 1493 ); + info->reward_action_general2 = getField< uint8_t >( row, 1494 ); + info->reward_other = getField< uint8_t >( row, 1496 ); - info->instanced_content_unlock = getField< uint32_t >( row, 1497 ); + info->instanced_content_unlock = getField< uint32_t >( row, 1499 ); - info->reward_tome_type = getField< uint8_t >( row, 1499 ); - info->reward_tome_count = getField< uint8_t >( row, 1500 ); + info->reward_tome_type = getField< uint8_t >( row, 1501 ); + info->reward_tome_count = getField< uint8_t >( row, 1502 ); - info->reward_reputation = getField< uint8_t >( row, 1501 ); + info->reward_reputation = getField< uint8_t >( row, 1503 ); for( uint32_t i = 0; i < 50; i++ ) { - std::string entry = getField< std::string >( row, i + 47 ); + std::string entry = getField< std::string >( row, i + 49 ); if( entry.size() > 0 ) { info->script_entity.push_back( entry ); - uint32_t entry1 = getField< uint32_t >( row, i + 97 ); + uint32_t entry1 = getField< uint32_t >( row, i + 99 ); info->script_value.push_back( entry1 ); } } diff --git a/src/servers/Server_Common/Exd/ExdData.h b/src/servers/Server_Common/Exd/ExdData.h index f34e6b35..3a5dedf9 100644 --- a/src/servers/Server_Common/Exd/ExdData.h +++ b/src/servers/Server_Common/Exd/ExdData.h @@ -33,7 +33,7 @@ namespace Core { uint16_t map_id; int16_t discovery_index; bool is_two_byte; - uint8_t weather_rate; + uint16_t weather_rate; std::map< uint8_t, int32_t> weather_rate_map; int32_t aetheryte_index; @@ -255,7 +255,11 @@ namespace Core { bool affects_position; // 47 + bool no_effect_in_battle; // 60 + + bool is_aoe; // Internal only + }; struct EventItemInfo @@ -269,7 +273,16 @@ namespace Core { struct StatusEffectInfo { uint32_t id; - std::string name; //0 + std::string name; // 0 + bool lock_movement; // 7 + bool lock_actions; // 9 + bool lock_control; // 10 + bool transfiguration; // 11 + bool can_dispel; // 13 + bool is_permanent; // 15 + bool inflicted_by_actor; // 17 + bool is_fc_buff; // 21 + bool invisibility; // 22 }; class ExdData diff --git a/src/servers/Server_Common/Network/PacketDef/Chat/ServerChatDef.h b/src/servers/Server_Common/Network/PacketDef/Chat/ServerChatDef.h index 7eed0dd7..219b3706 100644 --- a/src/servers/Server_Common/Network/PacketDef/Chat/ServerChatDef.h +++ b/src/servers/Server_Common/Network/PacketDef/Chat/ServerChatDef.h @@ -19,6 +19,8 @@ struct FFXIVIpcTell : FFXIVIpcBasePacket uint16_t u2a; uint16_t u2b; uint8_t preName; + uint8_t u3a; + uint8_t u3b; char receipientName[32]; char msg[1031]; }; diff --git a/src/servers/Server_Common/Network/PacketDef/Ipcs.h b/src/servers/Server_Common/Network/PacketDef/Ipcs.h index b4ade11c..23a7af23 100644 --- a/src/servers/Server_Common/Network/PacketDef/Ipcs.h +++ b/src/servers/Server_Common/Network/PacketDef/Ipcs.h @@ -44,88 +44,94 @@ namespace Packets { */ enum ServerZoneIpcType : uint16_t { - Ping = 0x0065, // updated for sb - Init = 0x0066, // updated for sb - Chat = 0x0067, // updated for sb + Ping = 0x0065, + Init = 0x0066, + Chat = 0x0067, ChatBanned = 0x006B, - Logout = 0x0077, // updated for sb + Logout = 0x0077, CFNotify = 0x0078, CFMemberStatus = 0x0079, CFDutyInfo = 0x007A, CFPlayerInNeed = 0x007F, - Playtime = 0x00AF, // updated for sb + Playtime = 0x00B7, // updated 4.1 SocialRequestError = 0x00AD, - SocialRequestResponse = 0x11AF, - CFRegistered = 0x00B0, - SocialList = 0x00B4, // updated for sb - UpdateSearchInfo = 0x00B6, // updated for sb - InitSearchInfo = 0x00B7, // updated for sb - ServerNotice = 0x00BC, // updated for sb - SetOnlineStatus = 0x00BD, // updated for sb - BlackList = 0x00CA, // updated for sb - LogMessage = 0x00D0, // updated for sb - LinkshellList = 0x00D1, // updated for sb - StatusEffectList = 0x00F0, // updated for sb - Effect = 0x00F1, // updated for sb + SocialRequestResponse = 0x00BB, // updated 4.1 + CFRegistered = 0x00B8, // updated 4.1 + SocialList = 0x00BE, // updated 4.1 + UpdateSearchInfo = 0x10BB, + InitSearchInfo = 0x00C1, // updated 4.1 + ServerNotice = 0x00C6, // updated 4.1 + SetOnlineStatus = 0x00C7, // test update + BlackList = 0x00D4, // updated 4.1 + LogMessage = 0x00D0, + + LinkshellList = 0x00DC, // updated 4.1 + StatusEffectList = 0x00FA, // updated 4.1 + + Effect = 0x00FB, // updated 4.1 GCAffiliation = 0x00FC, - ActorSetPos = 0x0114, // updated for sb - ActorCast = 0x0116, // updated for sb - PlayerSpawn = 0x0110, // updated for sb - NpcSpawn = 0x0111, // updated for sb - ActorMove = 0x0112, // updated for sb - HateList = 0x011A, // updated for sb borked - UpdateClassInfo = 0x011D, // updated for sb - InitUI = 0x011E, // updated for sb - PlayerStats = 0x011F, // updated for sb - ActorOwner = 0x0120, // updated for sb - PlayerStateFlags = 0x0121, // updated for sb - PlayerClassInfo = 0x0123, // updated for sb - ModelEquip = 0x0124, // updated for sb - ItemInfo = 0x0139, // updated for sb - ContainerInfo = 0x013A, // updated for sb - InventoryTransactionFinish = 0x013B, // updated for sb - InventoryTransaction = 0x013C, // updated for sb - CurrencyCrystalInfo = 0x013D, + ActorSetPos = 0x0120, // updated 4.1 + ActorCast = 0x0123, // updated 4.1 + PlayerSpawn = 0x011C, // updated 4.1 + NpcSpawn = 0x011D, // updated 4.1 + ActorMove = 0x011E, // updated 4.1 + HateList = 0x011A, + UpdateClassInfo = 0x011D, + InitUI = 0x012B, // updated 4.1 + ActorOwner = 0x012D, // updated 4.1 + PlayerStats = 0x0138, // updated 4.1 + PlayerStateFlags = 0x013A, // updated 4.1 + PlayerClassInfo = 0x013B, // updated 4.1 + ModelEquip = 0x013C, // updated 4.1 + ItemInfo = 0x014C, // updated 4.1 + ContainerInfo = 0x014D, // updated 4.1 + InventoryTransactionFinish = 0x014E, // updated 4.1 + InventoryTransaction = 0x014F, // updated 4.1 + CurrencyCrystalInfo = 0x0150, // updated 4.1 InventoryActionAck = 0x1139, - UpdateInventorySlot = 0x0140, // updated for sb + UpdateInventorySlot = 0x0153, // updated 4.1 AddStatusEffect = 0x0141, - ActorControl142 = 0x0142, // unchanged for sb - ActorControl143 = 0x0143, // unchanged for sb - ActorControl144 = 0x0144, // unchanged for sb - UpdateHpMpTp = 0x0145, // unchanged for sb + ActorControl142 = 0x0142, // updated 4.1 + ActorControl143 = 0x0143, // updated 4.1 + ActorControl144 = 0x0144, // updated 4.1 + UpdateHpMpTp = 0x0145, // updated 4.1 - EventPlay = 0x0154, // updated for sb - EventStart = 0x015D, // updated for sb - EventFinish = 0x015E, // updated for sb + EventPlay = 0x0160, // updated 4.1 + EventStart = 0x0169, // updated 4.1 + EventFinish = 0x016A, // updated 4.1 - EventLinkshell = 0x0169, + EventLinkshell = 0x1169, - QuestActiveList = 0x0171, // updated for sb - QuestUpdate = 0x0172, // updated for sb - QuestCompleteList = 0x0173, // updated for sb - QuestFinish = 0x0174, // updated for sb + QuestActiveList = 0x017D, // updated 4.1 + QuestUpdate = 0x017E, // updated 4.1 + QuestCompleteList = 0x017F, // updated 4.1 + QuestFinish = 0x0180, // updated 4.1 QuestMessage = 0x0179, - QuestTracker = 0x0181, // updated for sb + + QuestTracker = 0x018D, // updated 4.1 ActorSpawn = 0x0190, // todo: split into playerspawn/actorspawn and use opcode 0x110/0x111 ActorFreeSpawn = 0x0191, // unchanged for sb InitZone = 0x019A, // unchanged for sb WeatherChange = 0x01AF, // updated for sb - Discovery = 0x01B2, // updated for sb + PlayerTitleList = 0x01BD, // updated for 4.1 + Discovery = 0x01BE, // updated for 4.1 - EorzeaTimeOffset = 0x01B4, + EorzeaTimeOffset = 0x01C0, // updated 4.1 + + EquipDisplayFlags = 0x01CC, // updated 4.1 CFAvailableContents = 0x01CF, - PrepareZoning = 0x0239, // updated for sb + PrepareZoning = 0x0248, // updated 4.1 // Unknown IPC types that still need to be sent // TODO: figure all these out properly - IPCTYPE_UNK_320 = 0x1FB, - IPCTYPE_UNK_322 = 0x1FD, + IPCTYPE_UNK_320 = 0x0207, // updated 4.1 + IPCTYPE_UNK_322 = 0x0209, // updated 4.1 }; @@ -138,53 +144,57 @@ namespace Packets { { PingHandler = 0x0065, // updated for sb - InitHandler = 0x0066, // updated for sb - ChatHandler = 0x0067, // updated for sb + InitHandler = 0x0066, // updated 4.1 + ChatHandler = 0x00AD, // updated 4.1 - FinishLoadingHandler = 0x0069, // updated for sb + FinishLoadingHandler = 0x0069, // updated 4.1 CFCommenceHandler = 0x006F, CFRegisterDuty = 0x0071, CFRegisterRoulette = 0x0072, - PlayTimeHandler = 0x0073, // updated for sb - LogoutHandler = 0x0074, // updated for sb + PlayTimeHandler = 0x0073, // updated 4.1 + LogoutHandler = 0x0074, // updated 4.1 - CFDutyInfoHandler = 0x0078, + CFDutyInfoHandler = 0x0078, // updated 4.1 ?? - SocialReqSendHandler = 0x00A5, - SocialListHandler = 0x00AA, // updated for sb - SetSearchInfoHandler = 0x00AC, // updated for sb + SocialReqSendHandler = 0x00AE, // updated 4.1 + SocialListHandler = 0x00B3, // updated 4.1 + SetSearchInfoHandler = 0x00B5, // updated 4.1 - ReqSearchInfoHandler = 0x00AD, + ReqSearchInfoHandler = 0x00B6, // updated 4.1 - BlackListHandler = 0x00B7, // updated for sb + BlackListHandler = 0x00C0, // updated 4.1 - LinkshellListHandler = 0x00BF, // updated for sb + LinkshellListHandler = 0x00C8, // updated 4.1 - FcInfoReqHandler = 0x0100, // updated for sb + FcInfoReqHandler = 0x0109, // updated 4.1 - ZoneLineHandler = 0x0107, // updated for sb - ActionHandler = 0x0108, // updated for sb - DiscoveryHandler = 0x0109, // updated for sb + ZoneLineHandler = 0x0110, // updated 4.1 + ActionHandler = 0x0111, // updated 4.1 + DiscoveryHandler = 0x0112, // updated 4.1 - SkillHandler = 0x010B, // updated for sb - GMCommand1 = 0x010C, // updated for sb - GMCommand2 = 0x010D, // updated for sb - UpdatePositionHandler = 0x010F, // updated for sb + SkillHandler = 0x0114, // updated 4.1 + GMCommand1 = 0x0115, // updated 4.1 ?? + GMCommand2 = 0x0116, // updated 4.1 ?? + UpdatePositionHandler = 0x0118, // updated 4.1 - InventoryModifyHandler = 0x0116, // updated for sb + InventoryModifyHandler = 0x011F, // updated 4.1 - TalkEventHandler = 0x011F, // updated for sb - EmoteEventHandler = 0x0120, // updated for sb - WithinRangeEventHandler = 0x0121, // updated for sb - OutOfRangeEventHandler = 0x0122, // updated for sb - EnterTeriEventHandler = 0x0123, // updated for sb + TalkEventHandler = 0x0128, // updated 4.1 + EmoteEventHandler = 0x0129, // updated 4.1 + WithinRangeEventHandler = 0x012A, // updated 4.1 + OutOfRangeEventHandler = 0x012B, // updated 4.1 + EnterTeriEventHandler = 0x012C, // updated 4.1 - ReturnEventHandler = 0x0128, - TradeReturnEventHandler = 0x0129, + ReturnEventHandler = 0x0131, // updated 4.1 + TradeReturnEventHandler = 0x0132, // updated 4.1 + + + LinkshellEventHandler = 0x0144, // updated 4.1 ?? + LinkshellEventHandler1 = 0x0145, // updated 4.1 ?? + + ReqEquipDisplayFlagsChange = 0x014C, // updated 4.1 ?? - LinkshellEventHandler = 0x013B, - LinkshellEventHandler1 = 0x013C, }; //////////////////////////////////////////////////////////////////////////////// diff --git a/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h b/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h index 10a34cd0..c715b588 100644 --- a/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h @@ -340,15 +340,15 @@ struct FFXIVIpcPlayerSpawn : FFXIVIpcBasePacket { uint16_t title; uint16_t u1b; - uint8_t gmRank; - uint8_t u2ab; uint8_t u2b; + uint8_t u2ab; + uint8_t gmRank; uint8_t onlineStatus; - uint8_t pose; + uint8_t u3a; uint8_t u3b; uint8_t u3c; - uint8_t u3d; + uint8_t pose; uint32_t u4; @@ -368,8 +368,8 @@ struct FFXIVIpcPlayerSpawn : FFXIVIpcBasePacket uint32_t u20; uint32_t ownerId; uint32_t u22; - uint32_t hPCurr; uint32_t hPMax; + uint32_t hPCurr; uint32_t displayFlags; uint16_t fateID; uint16_t mPCurr; @@ -639,6 +639,14 @@ struct FFXIVIpcUpdateClassInfo : FFXIVIpcBasePacket uint32_t restedExp; }; +/** + * Structural representation of the packet sent by the server + * to send the titles available to the player + */ +struct FFXIVIpcPlayerTitleList : FFXIVIpcBasePacket +{ + uint8_t titleList[48]; +}; /** * Structural representation of the packet sent by the server @@ -718,7 +726,7 @@ struct FFXIVIpcInitUI : FFXIVIpcBasePacket uint16_t unknown_005; uint8_t unknown_114; uint8_t padding_114; - uint8_t unknown_1141[52]; + uint8_t unknown_1141[61]; uint8_t preNamePadding; char name[32]; uint8_t unknown_54[16]; @@ -781,7 +789,7 @@ struct FFXIVIpcInitUI : FFXIVIpcBasePacket uint8_t unknownRest[32]; uint8_t tripleTriadCards[26]; uint8_t unknownRest1[21]; - uint8_t orchestrionMask[19]; + uint8_t orchestrionMask[38]; uint8_t hallOfNoviceCompleteMask[3]; uint8_t unknownMask2[11]; uint8_t unknownMask3[16]; @@ -1286,6 +1294,14 @@ struct FFXIVIpcEorzeaTimeOffset : FFXIVIpcBasePacket uint64_t timestamp; }; +/** +* Structural representation of the packet sent by the server +* to set the gear show/hide status of a character +*/ +struct FFXIVIpcEquipDisplayFlags : FFXIVIpcBasePacket +{ + uint8_t bitmask; +}; } /* Server */ diff --git a/src/servers/Server_Zone/Action/ActionCast.cpp b/src/servers/Server_Zone/Action/ActionCast.cpp index df132950..a28125c7 100644 --- a/src/servers/Server_Zone/Action/ActionCast.cpp +++ b/src/servers/Server_Zone/Action/ActionCast.cpp @@ -92,7 +92,11 @@ void Core::Action::ActionCast::onInterrupt() m_pSource->getAsPlayer()->sendStateFlags(); auto control = ActorControlPacket142( m_pSource->getId(), ActorControlType::CastInterrupt, - 0x219, 1, m_id, 1 ); + 0x219, 1, m_id, 0 ); + + // Note: When cast interrupt from taking too much damage, set the last value to 1. This enables the cast interrupt effect. Example: + // auto control = ActorControlPacket142( m_pSource->getId(), ActorControlType::CastInterrupt, 0x219, 1, m_id, 0 ); + m_pSource->sendToInRangeSet( control, true ); } diff --git a/src/servers/Server_Zone/Actor/Actor.cpp b/src/servers/Server_Zone/Actor/Actor.cpp index 977cdd6e..33f20c6b 100644 --- a/src/servers/Server_Zone/Actor/Actor.cpp +++ b/src/servers/Server_Zone/Actor/Actor.cpp @@ -696,9 +696,13 @@ void Core::Entity::Actor::handleScriptSkill( uint32_t type, uint32_t actionId, u 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 ); + + pTarget.takeDamage( static_cast< uint32_t >( param1 ) ); + + if ( pTarget.isAlive() ) + pTarget.onActionHostile( shared_from_this() ); + } else { @@ -711,8 +715,11 @@ void Core::Entity::Actor::handleScriptSkill( uint32_t type, uint32_t actionId, u 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() ); + + if( pHitActor->isAlive() ) + pHitActor->onActionHostile( shared_from_this() ); // Debug if ( isPlayer() ) diff --git a/src/servers/Server_Zone/Actor/Actor.h b/src/servers/Server_Zone/Actor/Actor.h index 215ec666..5a784f28 100644 --- a/src/servers/Server_Zone/Actor/Actor.h +++ b/src/servers/Server_Zone/Actor/Actor.h @@ -43,6 +43,16 @@ public: 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, diff --git a/src/servers/Server_Zone/Actor/Player.cpp b/src/servers/Server_Zone/Actor/Player.cpp index a940667f..497fef25 100644 --- a/src/servers/Server_Zone/Actor/Player.cpp +++ b/src/servers/Server_Zone/Actor/Player.cpp @@ -385,6 +385,11 @@ void Core::Entity::Player::setZone( uint32_t zoneId ) sendInventory(); + if( isLogin() ) + { + queuePacket(ActorControlPacket143( getId(), SetCharaGearParamUI, m_equipDisplayFlags, 1 ) ); + } + // set flags, will be reset automatically by zoning ( only on client side though ) pPlayer->setStateFlag( PlayerStateFlag::BetweenAreas ); pPlayer->setStateFlag( PlayerStateFlag::BetweenAreas1 ); @@ -592,6 +597,17 @@ void Core::Entity::Player::learnAction( uint8_t actionId ) queuePacket( ActorControlPacket143( getId(), ToggleActionUnlock, actionId, 1 ) ); } +void Core::Entity::Player::learnSong( uint8_t songId, uint32_t itemId ) +{ + uint16_t index; + uint8_t value; + Util::valueToFlagByteIndexValue( songId, value, index ); + + m_orchestrion[index] |= value; + + queuePacket( ActorControlPacket143( getId(), ToggleOrchestrionUnlock, songId, 1, itemId ) ); +} + bool Core::Entity::Player::isActionLearned( uint8_t actionId ) const { uint16_t index; @@ -1154,6 +1170,11 @@ const uint8_t * Core::Entity::Player::getUnlockBitmask() const return m_unlocks; } +const uint8_t * Core::Entity::Player::getOrchestrionBitmask() const +{ + return m_orchestrion; +} + uint64_t Core::Entity::Player::getContentId() const { return m_contentId; @@ -1370,6 +1391,52 @@ void Core::Entity::Player::setIsLogin( bool bIsLogin ) m_bIsLogin = bIsLogin; } +uint8_t * Core::Entity::Player::getTitleList() +{ + return m_titleList; +} + +uint16_t Core::Entity::Player::getTitle() const +{ + return m_title; +} + +void Core::Entity::Player::addTitle( uint16_t titleId ) +{ + uint16_t index; + uint8_t value; + Util::valueToFlagByteIndexValue( titleId, value, index ); + + m_titleList[index] |= value; +} + +void Core::Entity::Player::setTitle( uint16_t titleId ) +{ + uint16_t index; + uint8_t value; + Util::valueToFlagByteIndexValue( titleId, value, index ); + + if ( ( m_titleList[index] & value ) == 0 ) // Player doesn't have title - bail + return; + + m_title = titleId; + + sendToInRangeSet( ActorControlPacket142( getId(), SetTitle, titleId ), true ); +} + +void Core::Entity::Player::setEquipDisplayFlags( uint8_t state ) +{ + m_equipDisplayFlags = state; + GamePacketNew< FFXIVIpcEquipDisplayFlags, ServerZoneIpcType > paramPacket( getId() ); + paramPacket.data().bitmask = m_equipDisplayFlags; + sendToInRangeSet( paramPacket, true ); +} + +uint8_t Core::Entity::Player::getEquipDisplayFlags() const +{ + return m_equipDisplayFlags; +} + void Core::Entity::Player::autoAttack( ActorPtr pTarget ) { diff --git a/src/servers/Server_Zone/Actor/Player.h b/src/servers/Server_Zone/Actor/Player.h index 0b503327..a1b02401 100644 --- a/src/servers/Server_Zone/Actor/Player.h +++ b/src/servers/Server_Zone/Actor/Player.h @@ -328,6 +328,18 @@ public: void teleport( uint16_t aetheryteId, uint8_t type = 1 ); /*! 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(); + /*! 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 ); + /*! change gear param state */ + void setEquipDisplayFlags( uint8_t state ); + /*! get gear param state and send update to inRangeSet */ + uint8_t getEquipDisplayFlags() const; void calculateStats() override; void sendStats(); @@ -361,10 +373,14 @@ public: void updateHowtosSeen( uint32_t howToId ); /*! learn an action / update the unlock bitmask. */ void learnAction( uint8_t actionId ); + /*! learn a song / update the unlock bitmask. */ + void learnSong( uint8_t songId, uint32_t itemId ); /*! check if an action is already unlocked in the bitmask. */ bool isActionLearned( uint8_t actionId ) const; /*! return a const pointer to the unlock bitmask array */ const uint8_t * getUnlockBitmask() const; + /*! return a const pointer to the orchestrion bitmask array */ + const uint8_t * getOrchestrionBitmask() const; // Spawn handling @@ -563,7 +579,8 @@ private: uint8_t status; } m_retainerInfo[8]; - uint8_t m_titleList[32]; + uint16_t m_title; + uint8_t m_titleList[48]; uint8_t m_achievement[16]; uint8_t m_howTo[33]; uint8_t m_minions[33]; @@ -581,6 +598,7 @@ private: uint32_t m_expArray[25]; uint8_t m_aetheryte[16]; uint8_t m_unlocks[64]; + uint8_t m_orchestrion[38]; uint8_t m_openingSequence; @@ -599,6 +617,8 @@ private: uint8_t m_gmRank; uint16_t zoneId; + uint8_t m_equipDisplayFlags; + bool m_bInCombat; bool m_bLoadingComplete; bool m_bAutoattack; diff --git a/src/servers/Server_Zone/Actor/PlayerSql.cpp b/src/servers/Server_Zone/Actor/PlayerSql.cpp index 4dc09627..e7da4aa1 100644 --- a/src/servers/Server_Zone/Actor/PlayerSql.cpp +++ b/src/servers/Server_Zone/Actor/PlayerSql.cpp @@ -386,7 +386,6 @@ void Core::Entity::Player::updateSql() stmt->setInt( 43, 0 ); // EquippedMannequin stmt->setInt( 44, 0 ); // DisplayFlags - std::vector< uint8_t > questCompleteVec( sizeof( m_questCompleteFlags ) ); memcpy( questCompleteVec.data(), m_questCompleteFlags, sizeof( m_questCompleteFlags ) ); stmt->setBinary( 45, questCompleteVec ); @@ -417,8 +416,6 @@ void Core::Entity::Player::updateSql() g_charaDb.execute( stmt ); - std::set< std::string > charaBaseSet; - std::set< std::string > charaDetailSet; std::set< std::string > charaClassSet; std::set< std::string > charaQuestSet; std::set< std::string > charaInfoSearchSet; diff --git a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp index 70c413c0..3a8805ed 100644 --- a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp +++ b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp @@ -118,6 +118,7 @@ void Core::DebugCommandHandler::scriptReload( char * data, Core::Entity::PlayerP boost::shared_ptr command ) { g_scriptMgr.reload(); + pPlayer->sendDebug( "Scripts reloaded." ); } void Core::DebugCommandHandler::set( char * data, Core::Entity::PlayerPtr pPlayer, boost::shared_ptr command ) @@ -182,13 +183,6 @@ void Core::DebugCommandHandler::set( char * data, Core::Entity::PlayerPtr pPlaye pPlayer->teleport( aetheryteId ); } - - else if( ( subCommand == "unlockaetheryte" ) && ( params != "" ) ) - { - for( uint8_t i = 0; i < 255; i++ ) - pPlayer->registerAetheryte( i ); - } - else if( ( subCommand == "discovery" ) && ( params != "" ) ) { int32_t map_id; @@ -304,13 +298,21 @@ void Core::DebugCommandHandler::add( char * data, Core::Entity::PlayerPtr pPlaye int32_t duration; uint16_t param; - sscanf( params.c_str(), "%d %d %hd", &id, &duration, ¶m ); + sscanf( params.c_str(), "%d %d %hu", &id, &duration, ¶m ); StatusEffect::StatusEffectPtr effect( new StatusEffect::StatusEffect( id, pPlayer, pPlayer, duration, 3000 ) ); effect->setParam( param ); pPlayer->addStatusEffect( effect ); } + else if ( subCommand == "title" ) + { + uint32_t titleId; + sscanf( params.c_str(), "%u", &titleId ); + + pPlayer->addTitle( titleId ); + pPlayer->sendNotice( "Added title (ID: " + std::to_string( titleId ) + ")" ); + } else if( subCommand == "spawn" ) { int32_t model, name; @@ -333,7 +335,6 @@ void Core::DebugCommandHandler::add( char * data, Core::Entity::PlayerPtr pPlaye pPlayer->queuePacket( pPe ); } else if( subCommand == "actrl" ) - { // temporary research packet diff --git a/src/servers/Server_Zone/Network/GameConnection.cpp b/src/servers/Server_Zone/Network/GameConnection.cpp index 0220b713..f4c799e8 100644 --- a/src/servers/Server_Zone/Network/GameConnection.cpp +++ b/src/servers/Server_Zone/Network/GameConnection.cpp @@ -93,8 +93,9 @@ Core::Network::GameConnection::GameConnection( Core::Network::HivePtr pHive, setZoneHandler( ClientZoneIpcType::CFRegisterRoulette, "CFRegisterRoulette", &GameConnection::cfRegisterRoulette ); setZoneHandler( ClientZoneIpcType::CFCommenceHandler, "CFDutyAccepted", &GameConnection::cfDutyAccepted); + setZoneHandler( ClientZoneIpcType::ReqEquipDisplayFlagsChange, "ReqEquipDisplayFlagsChange",&GameConnection::reqEquipDisplayFlagsHandler); - setChatHandler( ClientChatIpcType::TellReq, "TellReq", &GameConnection::tellHandler); + setChatHandler( ClientChatIpcType::TellReq, "TellReq", &GameConnection::tellHandler); } @@ -116,7 +117,7 @@ void Core::Network::GameConnection::OnAccept( const std::string & host, uint16_t void Core::Network::GameConnection::OnDisconnect() { - g_log.debug( "DISCONNECT" ); + g_log.debug( "GameConnection DISCONNECT" ); m_pSession = nullptr; } @@ -167,7 +168,7 @@ void Core::Network::GameConnection::OnRecv( std::vector< uint8_t > & buffer ) void Core::Network::GameConnection::OnError( const boost::system::error_code & error ) { - g_log.debug( "ERROR" ); + g_log.debug( "GameConnection ERROR: " + error.message() ); } void Core::Network::GameConnection::queueInPacket( Core::Network::Packets::GamePacketPtr inPacket ) @@ -380,10 +381,21 @@ void Core::Network::GameConnection::handlePackets( const Core::Network::Packets: { g_log.info( "[" + std::string( id ) + "] Session not registered, creating" ); // return; - g_serverZone.createSession( playerId ); + if( !g_serverZone.createSession( playerId ) ) + { + Disconnect(); + return; + } session = g_serverZone.getSession( playerId ); } + if( !session->isValid() ) //TODO: Catch more things in lobby and send real errors + { + g_log.error( "[" + std::string(id) + "] Session INVALID, disconnecting" ); + Disconnect(); + return; + } + // if not set, set the session for this connection if( !m_pSession && session ) m_pSession = session; @@ -416,8 +428,6 @@ void Core::Network::GameConnection::handlePackets( const Core::Network::Packets: sendSinglePacket( &pPe ); } - - break; } diff --git a/src/servers/Server_Zone/Network/GameConnection.h b/src/servers/Server_Zone/Network/GameConnection.h index d9156583..d89ae491 100644 --- a/src/servers/Server_Zone/Network/GameConnection.h +++ b/src/servers/Server_Zone/Network/GameConnection.h @@ -116,10 +116,10 @@ public: DECLARE_HANDLER( gm1Handler ); DECLARE_HANDLER( gm2Handler ); + DECLARE_HANDLER( reqEquipDisplayFlagsHandler ); + DECLARE_HANDLER( tellHandler ); - - }; diff --git a/src/servers/Server_Zone/Network/Handlers/ActionHandler.cpp b/src/servers/Server_Zone/Network/Handlers/ActionHandler.cpp index f0236f69..cf0b030a 100644 --- a/src/servers/Server_Zone/Network/Handlers/ActionHandler.cpp +++ b/src/servers/Server_Zone/Network/Handlers/ActionHandler.cpp @@ -114,10 +114,23 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in } case 0x69: // Cancel cast { - if( pPlayer->checkAction() ) + if( pPlayer->getCurrentAction() != nullptr ) pPlayer->getCurrentAction()->setInterrupted(); break; } + case 0x12E: // Set player title + { + pPlayer->setTitle( param1 ); + break; + } + case 0x12F: // Get title list + { + GamePacketNew< FFXIVIpcPlayerTitleList, ServerZoneIpcType > titleListPacket( pPlayer->getId() ); + memcpy( titleListPacket.data().titleList, pPlayer->getTitleList(), sizeof( titleListPacket.data().titleList ) ); + + pPlayer->queuePacket( titleListPacket ); + break; + } case 0x133: // Update howtos seen { uint32_t howToId = static_cast< uint32_t >( param1 ); @@ -216,6 +229,10 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in } break; } - + default: + { + g_log.debug( "[" + std::to_string( m_pSession->getId() ) + "] Unhandled action: " + + boost::str( boost::format( "%|04X|" ) % (uint32_t) ( commandId & 0xFFFF ) ) ); + } } } diff --git a/src/servers/Server_Zone/Network/Handlers/GMCommandHandlers.cpp b/src/servers/Server_Zone/Network/Handlers/GMCommandHandlers.cpp index fb962ee0..231f9b00 100644 --- a/src/servers/Server_Zone/Network/Handlers/GMCommandHandlers.cpp +++ b/src/servers/Server_Zone/Network/Handlers/GMCommandHandlers.cpp @@ -72,6 +72,8 @@ enum GmCommand Exp = 0x0068, Inv = 0x006A, + Orchestrion = 0x0074, + Item = 0x00C8, Gil = 0x00C9, Collect = 0x00CA, @@ -84,6 +86,7 @@ enum GmCommand QuestInspect = 0x0131, GC = 0x0154, GCRank = 0x0155, + Aetheryte = 0x015E, Teri = 0x0258, TeriInfo = 0x025D, Jump = 0x025E, @@ -364,6 +367,52 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac " was switched." ); break; } + case GmCommand::Aetheryte: + { + if( param1 == 0 ) + { + if( param2 == 0 ) + { + for( uint8_t i = 0; i < 255; i++ ) + targetActor->getAsPlayer()->registerAetheryte( i ); + + pPlayer->sendNotice( "All Aetherytes for " + targetPlayer->getName() + + " were turned on." ); + } + else + { + targetActor->getAsPlayer()->registerAetheryte( param2 ); + pPlayer->sendNotice( "Aetheryte " + std::to_string( param2 ) + " for " + targetPlayer->getName() + + " was turned on." ); + } + } + + + break; + } + case GmCommand::Orchestrion: + { + if( param1 == 1 ) + { + if( param2 == 0 ) + { + for( uint8_t i = 0; i < 255; i++ ) + targetActor->getAsPlayer()->learnSong( i, 0 ); + + pPlayer->sendNotice( "All Songs for " + targetPlayer->getName() + + " were turned on." ); + } + else + { + targetActor->getAsPlayer()->learnSong( param2, 0 ); + pPlayer->sendNotice( "Song " + std::to_string( param2 ) + " for " + targetPlayer->getName() + + " was turned on." ); + } + } + + + break; + } default: pPlayer->sendUrgent( "GM1 Command not implemented: " + std::to_string( commandId ) ); diff --git a/src/servers/Server_Zone/Network/Handlers/PacketHandlers.cpp b/src/servers/Server_Zone/Network/Handlers/PacketHandlers.cpp index bccb7a87..82060376 100644 --- a/src/servers/Server_Zone/Network/Handlers/PacketHandlers.cpp +++ b/src/servers/Server_Zone/Network/Handlers/PacketHandlers.cpp @@ -283,7 +283,11 @@ void Core::Network::GameConnection::updatePositionHandler( const Packets::GamePa } - +void Core::Network::GameConnection::reqEquipDisplayFlagsHandler( const Packets::GamePacket& inPacket, + Entity::PlayerPtr pPlayer ) +{ + pPlayer->setEquipDisplayFlags( inPacket.getValAt< uint8_t >( 0x20 ) ); +} void Core::Network::GameConnection::zoneLineHandler( const Packets::GamePacket& inPacket, Entity::PlayerPtr pPlayer ) diff --git a/src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h b/src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h index 1a4d06e5..60b69f1d 100644 --- a/src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h +++ b/src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h @@ -42,7 +42,7 @@ private: m_data.namedayMonth = player->getBirthMonth(); m_data.namedayDay = player->getBirthDay(); // TODO: Support grand company status. - m_data.grandCompany = static_cast< Common::GrandCompany >( player->getStartTown() ); + m_data.grandCompany = static_cast< Common::GrandCompany >( player->getGc() ); //m_data.gcRank = GCRank::None; // TODO: Support starting city. @@ -62,6 +62,8 @@ private: m_data.exp[i] = player->getExpArray()[i]; } + memcpy( m_data.orchestrionMask, player->getOrchestrionBitmask(), sizeof( m_data.orchestrionMask ) ); + memcpy( m_data.unlockBitmask, player->getUnlockBitmask(), sizeof( m_data.unlockBitmask ) ); memcpy( m_data.discovery, player->getDiscoveryBitmask(), sizeof( m_data.discovery ) ); diff --git a/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h b/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h index 5bd39a09..f96160f6 100644 --- a/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h +++ b/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h @@ -36,41 +36,49 @@ namespace Server { // TODO: temporary gm rank //m_data.gmRank = 0xff; - - m_data.currentMount = 0; m_data.classJob = pPlayer->getClass(); //m_data.status = static_cast< uint8_t >( pPlayer->getStatus() ); + m_data.hPCurr = pPlayer->getHp(); m_data.mPCurr = pPlayer->getMp(); m_data.tPCurr = pPlayer->getTp(); m_data.hPMax = pPlayer->getMaxHp(); m_data.mPMax = pPlayer->getMaxMp(); - m_data.gmRank = pPlayer->getGmRank(); + //m_data.tPMax = 3000; m_data.level = pPlayer->getLevel(); + m_data.gmRank = pPlayer->getGmRank(); + m_data.pose = 0; + memcpy( m_data.look, pPlayer->getLookArray(), 26 ); + auto item = pPlayer->getInventory()->getItemAt( Inventory::GearSet0, Inventory::EquipSlot::MainHand ); if( item ) m_data.mainWeaponModel = item->getModelId1(); m_data.secWeaponModel = pPlayer->getModelSubWeapon(); + m_data.models[0] = pPlayer->getModelForSlot( Inventory::EquipSlot::Head ); m_data.models[1] = pPlayer->getModelForSlot( Inventory::EquipSlot::Body ); m_data.models[2] = pPlayer->getModelForSlot( Inventory::EquipSlot::Hands ); m_data.models[3] = pPlayer->getModelForSlot( Inventory::EquipSlot::Legs ); m_data.models[4] = pPlayer->getModelForSlot( Inventory::EquipSlot::Feet ); strcpy( m_data.name, pPlayer->getName().c_str() ); + m_data.pos.x = pPlayer->getPos().x; m_data.pos.y = pPlayer->getPos().y; m_data.pos.z = pPlayer->getPos().z; - m_data.voice = pPlayer->getVoiceId(); - m_data.rotation = Math::Util::floatToUInt16Rot( pPlayer->getRotation() ); + + + m_data.title = pPlayer->getTitle(); + m_data.voice = pPlayer->getVoiceId(); + m_data.currentMount = 0; m_data.onlineStatus = static_cast< uint8_t >( pPlayer->getOnlineStatus() ); //m_data.u23 = 0x04; //m_data.u24 = 256; - m_data.state = 1; + m_data.state = static_cast< uint8_t >( pPlayer->getStatus() ); m_data.type = 1; if( pTarget == pPlayer ) { @@ -85,7 +93,22 @@ namespace Server { if( pPlayer->getZoningType() != Common::ZoneingType::None ) { - m_data.displayFlags |= 0x20; + m_data.displayFlags |= Entity::Actor::DisplayFlags::Invisible; + } + + if( pPlayer->getEquipDisplayFlags() & Core::Common::EquipDisplayFlags::HideHead ) + { + m_data.displayFlags |= Entity::Actor::DisplayFlags::HideHead; + } + + if( pPlayer->getEquipDisplayFlags() & Core::Common::EquipDisplayFlags::HideWeapon ) + { + m_data.displayFlags |= Entity::Actor::DisplayFlags::HideWeapon; + } + + if( pPlayer->getEquipDisplayFlags() & Core::Common::EquipDisplayFlags::Visor ) + { + m_data.displayFlags |= Entity::Actor::DisplayFlags::Visor; } m_data.targetId = pPlayer->getTargetId(); diff --git a/src/servers/Server_Zone/Session.cpp b/src/servers/Server_Zone/Session.cpp index e7d0b851..7df173d9 100644 --- a/src/servers/Server_Zone/Session.cpp +++ b/src/servers/Server_Zone/Session.cpp @@ -11,6 +11,7 @@ Core::Session::Session( uint32_t sessionId ) : m_sessionId( sessionId ) , m_lastDataTime( static_cast< uint32_t >( Util::getTimeSeconds() ) ) , m_lastSqlTime( static_cast< uint32_t >( Util::getTimeSeconds() ) ) + , m_isValid( false ) { // boost::posix_time::ptime now = boost::date_time::not_a_date_time; @@ -50,7 +51,15 @@ bool Core::Session::loadPlayer() m_pPlayer = Entity::PlayerPtr( new Entity::Player() ); - return m_pPlayer->load(m_sessionId, shared_from_this() ); + if( !m_pPlayer->load( m_sessionId, shared_from_this() ) ) + { + m_isValid = false; + return false; + } + + m_isValid = true; + + return true; } @@ -59,6 +68,9 @@ void Core::Session::close() if( m_pZoneConnection ) m_pZoneConnection->Disconnect(); + if( m_pChatConnection ) + m_pChatConnection->Disconnect(); + // remove the session from the player if( m_pPlayer ) // reset the zone, so the zone handler knows to remove the actor @@ -80,6 +92,11 @@ uint32_t Core::Session::getLastSqlTime() const return m_lastSqlTime; } +bool Core::Session::isValid() const +{ + return m_isValid; +} + void Core::Session::updateLastDataTime() { m_lastDataTime = static_cast< uint32_t >( Util::getTimeSeconds() ); diff --git a/src/servers/Server_Zone/Session.h b/src/servers/Server_Zone/Session.h index 4ac7d433..cd2a1c7f 100644 --- a/src/servers/Server_Zone/Session.h +++ b/src/servers/Server_Zone/Session.h @@ -37,6 +37,8 @@ namespace Core { void update(); + bool isValid() const; + Entity::PlayerPtr getPlayer() const; private: @@ -47,6 +49,7 @@ namespace Core { uint32_t m_lastDataTime; uint32_t m_lastSqlTime; + bool m_isValid; Network::GameConnectionPtr m_pZoneConnection; Network::GameConnectionPtr m_pChatConnection;