From 8c488519e5819824a8f26c634b6736fb50bf2c22 Mon Sep 17 00:00:00 2001 From: Zach Toogood Date: Tue, 26 Sep 2023 10:02:15 +0100 Subject: [PATCH] Start on Monstrosity --- scripts/commands/monstrosity.lua | 19 ++++ scripts/globals/monstrosity.lua | 68 ++++++++++++ .../hiddenQuests/Monstrosity_Unlock.lua | 103 ++++++++++++++++++ scripts/zones/Feretory/Zone.lua | 12 +- settings/default/main.lua | 3 + src/map/CMakeLists.txt | 2 + src/map/entities/charentity.cpp | 3 +- src/map/entities/charentity.h | 4 +- src/map/lua/lua_baseentity.cpp | 47 -------- src/map/lua/lua_baseentity.h | 3 +- src/map/monstrosity.cpp | 61 +++++++++++ src/map/monstrosity.h | 46 ++++++++ src/map/packets/char.cpp | 5 +- src/map/packets/char_appearance.cpp | 5 +- src/map/packets/char_health.cpp | 7 ++ src/map/packets/char_update.cpp | 10 ++ src/map/packets/monipulator1.cpp | 18 ++- src/map/packets/monipulator2.cpp | 4 + src/map/packets/zone_in.cpp | 34 ++++-- src/map/zone.cpp | 3 + 20 files changed, 384 insertions(+), 73 deletions(-) create mode 100644 scripts/commands/monstrosity.lua create mode 100644 scripts/globals/monstrosity.lua create mode 100644 scripts/quests/hiddenQuests/Monstrosity_Unlock.lua create mode 100644 src/map/monstrosity.cpp create mode 100644 src/map/monstrosity.h diff --git a/scripts/commands/monstrosity.lua b/scripts/commands/monstrosity.lua new file mode 100644 index 00000000000..ea1fc728989 --- /dev/null +++ b/scripts/commands/monstrosity.lua @@ -0,0 +1,19 @@ +local commandObj = {} + +commandObj.cmdprops = +{ + permission = 1, + parameters = '' +} + +commandObj.onTrigger = function(player) + if player:getCharVar('MONSTROSITY_START') == 1 then + player:setCharVar('MONSTROSITY_START', 0) + else + player:setCharVar('MONSTROSITY_START', 1) + end + + player:setPos(player:getXPos(), player:getYPos(), player:getZPos(), player:getRotPos(), player:getZoneID()) +end + +return commandObj diff --git a/scripts/globals/monstrosity.lua b/scripts/globals/monstrosity.lua new file mode 100644 index 00000000000..cbb17150e40 --- /dev/null +++ b/scripts/globals/monstrosity.lua @@ -0,0 +1,68 @@ +----------------------------------- +-- Monstrosity +----------------------------------- +require('scripts/globals/npc_util') +require('scripts/globals/quests') +----------------------------------- +xi = xi or {} +xi.monstrosity = xi.monstrosity or {} + +----------------------------------- +-- Odyssean Passage +----------------------------------- + +xi.monstrosity.odysseanPassageOnTrigger = function(player, npc) + -- TODO: Handle xi.settings.main.ENABLE_MONSTROSITY + + -- TODO: If passage in the overworld, do logic X + local isMonstrosityUnlocked = player:hasKeyItem(xi.keyItem.RING_OF_SUPERNAL_DISJUNCTION) + if isMonstrosityUnlocked then + player:startEvent(883) + end + + -- TODO: If passage in Feretory, do logic Y + -- In Feretory: Event 5 (0, 0, 0, 0, 0, 0, 0, 0) +end + +----------------------------------- +-- Feretory +----------------------------------- + +xi.monstrosity.feretoryOnZoneIn = function(player, prevZone) + -- TODO: Handle xi.settings.main.ENABLE_MONSTROSITY + + -- TODO: Rabbit, Mandy, and Lizard are all unlocked to begin with, but you + -- : start as whatever matching item you traded + + local cs = -1 + + player:setPos(-358.000, -3.400, -440.00, 63) + + return cs +end + +xi.monstrosity.feretoryOnEventUpdate = function(player, csid, option, npc) +end + +xi.monstrosity.feretoryOnEventFinish = function(player, csid, option, npc) +end + +----------------------------------- +-- Aengus (Feretory NPC) +----------------------------------- +-- Event 13 (As Lizard: 0, 0, 2, 0, 2, 90, 0, 0) + +----------------------------------- +-- Teyrnon (Feretory NPC) +----------------------------------- +-- Event 7 (As Lizard: 0, 0, 0, 0, 0, 0, 0, 0) + +----------------------------------- +-- Maccus (Feretory NPC) +----------------------------------- +-- Event 9 (As Lizard: 285, 2, 2, 0, 0, 0, 0, 0) + +----------------------------------- +-- Suibhne (Feretory NPC) +----------------------------------- +-- Event 11 (As Lizard: 1, 1, 0, 0, 0, 0, 0, 0) diff --git a/scripts/quests/hiddenQuests/Monstrosity_Unlock.lua b/scripts/quests/hiddenQuests/Monstrosity_Unlock.lua new file mode 100644 index 00000000000..cff0c7104c6 --- /dev/null +++ b/scripts/quests/hiddenQuests/Monstrosity_Unlock.lua @@ -0,0 +1,103 @@ +----------------------------------- +-- Unlocking Monstrosity +----------------------------------- + +local quest = HiddenQuest:new('MonstrosityUnlock') + +-- TODO: Handle xi.settings.main.ENABLE_MONSTROSITY +-- TODO: Hide completion behind a UniqueEvent flag + +quest.sections = +{ + -- Intro chatter + { + check = function(player, questVars, vars) + return quest:getVar(player, 'Prog') == 0 + end, + + [xi.zone.PASHHOW_MARSHLANDS] = + { + ['Suspicious_Hume'] = + { + onTrigger = function(player, npc) + return quest:progressEvent(40) + end, + }, + + onEventFinish = + { + [40] = function(player, csid, option, npc) + if option == 0 then + quest:setVar(player, 'Prog', 1) + end + end, + }, + }, + }, + + -- Reminder + { + check = function(player, questVars, vars) + return quest:getVar(player, 'Prog') == 1 + end, + + [xi.zone.PASHHOW_MARSHLANDS] = + { + ['Suspicious_Hume'] = + { + onTrigger = function(player, npc) + return quest:progressEvent(41) + end, + }, + }, + + [xi.zone.PORT_WINDURST] = + { + ['Suspicious_Tarutaru'] = + { + onTrade = function(player, npc, trade) + if + npcUtil.tradeHasExactly(trade, xi.item.LIZARD_TAIL) + then + return quest:progressEvent(881, 926, 0, 0, 0, 0, 0, 0, 4) + end + end, + + -- Reminder + onTrigger = function (player, npc) + return quest:progressEvent(880) + end, + }, + + onEventFinish = + { + [881] = function(player, csid, option, npc) + if option == 0 then + quest:setVar(player, 'Prog', 2) + npcUtil.giveKeyItem(player, xi.ki.RING_OF_SUPERNAL_DISJUNCTION) + end + end, + }, + }, + }, + + -- Intro chatter + { + check = function(player, questVars, vars) + return quest:getVar(player, 'Prog') == 2 + end, + + [xi.zone.PORT_WINDURST] = + { + ['Suspicious_Tarutaru'] = + { + -- Reminder + onTrigger = function (player, npc) + return quest:progressEvent(882) + end, + }, + }, + }, +} + +return quest diff --git a/scripts/zones/Feretory/Zone.lua b/scripts/zones/Feretory/Zone.lua index dbd7762b148..c28aa4ad28e 100644 --- a/scripts/zones/Feretory/Zone.lua +++ b/scripts/zones/Feretory/Zone.lua @@ -1,26 +1,28 @@ ----------------------------------- -- Zone: Feretory ----------------------------------- +require('scripts/globals/monstrosity') +----------------------------------- local zoneObject = {} zoneObject.onInitialize = function(zone) + -- Unused end zoneObject.onZoneIn = function(player, prevZone) - local cs = -1 - - player:setPos(-358.000, -3.400, -440.00, 63) - - return cs + return xi.monstrosity.feretoryOnZoneIn(player, prevZone) end zoneObject.onTriggerAreaEnter = function(player, triggerArea) + -- Unused end zoneObject.onEventUpdate = function(player, csid, option, npc) + xi.monstrosity.feretoryOnEventUpdate(player, csid, option, npc) end zoneObject.onEventFinish = function(player, csid, option, npc) + xi.monstrosity.feretoryOnEventFinish(player, csid, option, npc) end return zoneObject diff --git a/settings/default/main.lua b/settings/default/main.lua index bcad16499a4..b9b3ddd6692 100644 --- a/settings/default/main.lua +++ b/settings/default/main.lua @@ -69,6 +69,9 @@ xi.settings.main = -- VoidWalker ENABLE_VOIDWALKER = 1, + -- VoidWalker + ENABLE_MONSTROSITY = 1, + -- TREASURE CASKETS -- Retail droprate = 0.1 (10%) with no other effects active -- Set to 0 to disable caskets. diff --git a/src/map/CMakeLists.txt b/src/map/CMakeLists.txt index 2d0d14b2f73..fcdbdd1102a 100644 --- a/src/map/CMakeLists.txt +++ b/src/map/CMakeLists.txt @@ -88,6 +88,8 @@ set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/mobskill.h ${CMAKE_CURRENT_SOURCE_DIR}/modifier.cpp ${CMAKE_CURRENT_SOURCE_DIR}/modifier.h + ${CMAKE_CURRENT_SOURCE_DIR}/monstrosity.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/monstrosity.h ${CMAKE_CURRENT_SOURCE_DIR}/navmesh.cpp ${CMAKE_CURRENT_SOURCE_DIR}/navmesh.h ${CMAKE_CURRENT_SOURCE_DIR}/notoriety_container.cpp diff --git a/src/map/entities/charentity.cpp b/src/map/entities/charentity.cpp index e9459ed7c84..09db7b43d94 100644 --- a/src/map/entities/charentity.cpp +++ b/src/map/entities/charentity.cpp @@ -173,8 +173,9 @@ CCharEntity::CCharEntity() m_mkeCurrent = 0; m_asaCurrent = 0; + m_PMonstrosity = nullptr; + m_Costume = 0; - m_Monstrosity = 0; m_hasTractor = 0; m_hasRaise = 0; m_weaknessLvl = 0; diff --git a/src/map/entities/charentity.h b/src/map/entities/charentity.h index cd3b11dc451..06a2901583c 100644 --- a/src/map/entities/charentity.h +++ b/src/map/entities/charentity.h @@ -23,6 +23,7 @@ along with this program. If not, see http://www.gnu.org/licenses/ #define _CHARENTITY_H #include "event_info.h" +#include "monstrosity.h" #include "packets/char.h" #include "packets/entity_update.h" @@ -447,10 +448,11 @@ class CCharEntity : public CBattleEntity EntityID_t BazaarID{}; // Pointer to the bazaar we are browsing. BazaarList_t BazaarCustomers; // Array holding the IDs of the current customers + std::unique_ptr m_PMonstrosity; + uint32 m_InsideTriggerAreaID; // The ID of the trigger area the character is inside uint8 m_LevelRestriction; // Character level limit uint16 m_Costume; - uint16 m_Monstrosity; // Monstrosity model ID uint32 m_AHHistoryTimestamp; uint32 m_DeathTimestamp; time_point m_deathSyncTime; // Timer used for sending an update packet at a regular interval while the character is dead diff --git a/src/map/lua/lua_baseentity.cpp b/src/map/lua/lua_baseentity.cpp index 725c4160e19..a9067bfab24 100644 --- a/src/map/lua/lua_baseentity.cpp +++ b/src/map/lua/lua_baseentity.cpp @@ -5191,50 +5191,6 @@ uint16 CLuaBaseEntity::getCostume() return PChar->m_Costume; } -/************************************************************************ - * Function: getCostume2() - * Purpose : Sets or returns a monstrosity costume - * Example : player:costume2( costumeId ) - * Notes : Not currently implemented - ************************************************************************/ - -uint16 CLuaBaseEntity::getCostume2() -{ - if (m_PBaseEntity->objtype != TYPE_PC) - { - ShowWarning("Invalid entity type calling function (%s).", m_PBaseEntity->GetName()); - return 0; - } - - auto* PChar = static_cast(m_PBaseEntity); - return PChar->m_Monstrosity; -} - -/************************************************************************ - * Function: setCostume2() - * Purpose : Sets or returns a monstrosity costume - * Example : player:costume2( costumeId ) - * Notes : Not currently implemented - ************************************************************************/ - -void CLuaBaseEntity::setCostume2(uint16 costume) -{ - if (m_PBaseEntity->objtype != TYPE_PC) - { - ShowWarning("Invalid entity type calling function (%s).", m_PBaseEntity->GetName()); - return; - } - - auto* PChar = static_cast(m_PBaseEntity); - - if (PChar->m_Monstrosity != costume && PChar->status != STATUS_TYPE::SHUTDOWN && PChar->status != STATUS_TYPE::DISAPPEAR) - { - PChar->m_Monstrosity = costume; - PChar->updatemask |= UPDATE_LOOK; - PChar->pushPacket(new CCharAppearancePacket(PChar)); - } -} - /************************************************************************ * Function: getAnimation() * Purpose : Returns the assigned default animation of an entity @@ -17063,9 +17019,6 @@ void CLuaBaseEntity::Register() SOL_REGISTER("setModelId", CLuaBaseEntity::setModelId); SOL_REGISTER("setCostume", CLuaBaseEntity::setCostume); SOL_REGISTER("getCostume", CLuaBaseEntity::getCostume); - SOL_REGISTER("getCostume2", CLuaBaseEntity::getCostume2); - SOL_REGISTER("setCostume2", CLuaBaseEntity::setCostume2); - SOL_REGISTER("getAnimation", CLuaBaseEntity::getAnimation); SOL_REGISTER("setAnimation", CLuaBaseEntity::setAnimation); SOL_REGISTER("getAnimationSub", CLuaBaseEntity::getAnimationSub); diff --git a/src/map/lua/lua_baseentity.h b/src/map/lua/lua_baseentity.h index d59d807ac82..6b43e4b8d66 100644 --- a/src/map/lua/lua_baseentity.h +++ b/src/map/lua/lua_baseentity.h @@ -271,8 +271,7 @@ class CLuaBaseEntity void setModelId(uint16 modelId, sol::object const& slotObj); void setCostume(uint16 costume); uint16 getCostume(); - uint16 getCostume2(); // monstrosity costume - void setCostume2(uint16 costume); + uint8 getAnimation(); void setAnimation(uint8 animation); uint8 getAnimationSub(); diff --git a/src/map/monstrosity.cpp b/src/map/monstrosity.cpp new file mode 100644 index 00000000000..1c5b5d65d9e --- /dev/null +++ b/src/map/monstrosity.cpp @@ -0,0 +1,61 @@ +/* +=========================================================================== + + Copyright (c) 2023 LandSandBoat Dev Teams + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/ + +=========================================================================== +*/ + +#include "monstrosity.h" + +#include "entities/charentity.h" +#include "utils/charutils.h" + +void monstrosity::HandleZoneIn(CCharEntity* PChar) +{ + // TODO: Check we're about to enter monstrosity, charvar, flag, etc. + if (charutils::GetCharVar(PChar, "MONSTROSITY_START") == 1) + { + PChar->m_PMonstrosity = std::make_unique(72, 11); + PChar->updatemask |= UPDATE_LOOK; + } +} + +uint32 monstrosity::GetPackedMonstrosityName(CCharEntity* PChar) +{ + // Monstrosity Name Ids? + // If populated, the monstrosity icon will appear + uint8 a = 0x1F; + + // Mob Type + // 0x80: Scorpion + // 0x81: Mandragora + uint8 b = 0x81; + + // Adjective 1 (optional) + // 01: Abashed + // CD: Tempest + // F5: Zenith + // F6: Zero + uint8 c = 0xF6; + + // Adjective 2 + // Same values as above + uint8 d = 0xCD; + + // Packed as LE + return (d << 24) + (c << 16) + (b << 8) + (a << 0); +} diff --git a/src/map/monstrosity.h b/src/map/monstrosity.h new file mode 100644 index 00000000000..110d5eabd2c --- /dev/null +++ b/src/map/monstrosity.h @@ -0,0 +1,46 @@ +/* +=========================================================================== + + Copyright (c) 2023 LandSandBoat Dev Teams + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see http://www.gnu.org/licenses/ + +=========================================================================== +*/ + +#pragma once + +#include "common/cbasetypes.h" + +class CCharEntity; + +namespace monstrosity +{ + struct MonstrosityData_t + { + public: + uint8 Face; + uint8 Race; + + MonstrosityData_t(uint8 face, uint8 race) + : Face(face) + , Race(race) + { + // + } + }; + + void HandleZoneIn(CCharEntity* PChar); + uint32 GetPackedMonstrosityName(CCharEntity* PChar); +} // monstrosity diff --git a/src/map/packets/char.cpp b/src/map/packets/char.cpp index 0e42b7ed3dc..20c29927d35 100644 --- a/src/map/packets/char.cpp +++ b/src/map/packets/char.cpp @@ -179,9 +179,10 @@ void CCharPacket::updateWith(CCharEntity* PChar, ENTITYUPDATE type, uint8 update ref(0x56) = look->sub + 0x7000; ref(0x58) = look->ranged + 0x8000; - if (PChar->m_Monstrosity != 0) + if (PChar->m_PMonstrosity != nullptr) { - ref(0x48) = PChar->m_Monstrosity; + ref(0x48) = PChar->m_PMonstrosity->Face; + ref(0x49) = PChar->m_PMonstrosity->Race; ref(0x58) = 0xFFFF; } } diff --git a/src/map/packets/char_appearance.cpp b/src/map/packets/char_appearance.cpp index e891fcbd5e7..8dd28e1265d 100644 --- a/src/map/packets/char_appearance.cpp +++ b/src/map/packets/char_appearance.cpp @@ -41,9 +41,10 @@ CCharAppearancePacket::CCharAppearancePacket(CCharEntity* PChar) ref(0x12) = look->sub + 0x7000; ref(0x14) = look->ranged + 0x8000; - if (PChar->m_Monstrosity != 0) + if (PChar->m_PMonstrosity != nullptr) { - ref(0x04) = PChar->m_Monstrosity; + ref(0x04) = PChar->m_PMonstrosity->Face; + ref(0x05) = PChar->m_PMonstrosity->Race; ref(0x14) = 0xFFFF; } } diff --git a/src/map/packets/char_health.cpp b/src/map/packets/char_health.cpp index 60b9120ffcc..823414f2230 100644 --- a/src/map/packets/char_health.cpp +++ b/src/map/packets/char_health.cpp @@ -26,6 +26,8 @@ #include "entities/charentity.h" #include "entities/trustentity.h" +#include "monstrosity.h" + CCharHealthPacket::CCharHealthPacket(CCharEntity* PChar) { this->setType(0xDF); @@ -42,6 +44,11 @@ CCharHealthPacket::CCharHealthPacket(CCharEntity* PChar) ref(0x16) = PChar->GetHPP(); ref(0x17) = PChar->GetMPP(); + if (PChar->m_PMonstrosity != nullptr) + { + ref(0x1C) = monstrosity::GetPackedMonstrosityName(PChar); + } + if (!(PChar->nameflags.flags & FLAG_ANON)) { ref(0x20) = PChar->GetMJob(); diff --git a/src/map/packets/char_update.cpp b/src/map/packets/char_update.cpp index d0f71c2b05f..9f23dbce60f 100644 --- a/src/map/packets/char_update.cpp +++ b/src/map/packets/char_update.cpp @@ -52,6 +52,7 @@ CCharUpdatePacket::CCharUpdatePacket(CCharEntity* PChar) { ref(0x2D) = 0x80; } + if (PChar->StatusEffectContainer->HasStatusEffect(EFFECT_SNEAK)) { ref(0x38) = 0x04; @@ -61,6 +62,7 @@ CCharUpdatePacket::CCharUpdatePacket(CCharEntity* PChar) { ref(0x38) |= 0x10; // Mentor flag. } + if (PChar->isNewPlayer()) { ref(0x38) |= 0x08; // New player ? @@ -81,10 +83,12 @@ CCharUpdatePacket::CCharUpdatePacket(CCharEntity* PChar) ref(0x32) = (LSColor.G << 4) + 15; ref(0x33) = (LSColor.B << 4) + 15; } + if (PChar->PPet != nullptr) { ref(0x34) = PChar->PPet->targid << 3; } + // Status flag: bit 4: frozen anim (terror), // bit 6/7/8 related to Ballista (6 set - normal, 7 set san d'oria, 6+7 set bastok, 8 set windurst) uint8 flag = (static_cast(PChar->allegiance) << 5); @@ -107,6 +111,7 @@ CCharUpdatePacket::CCharUpdatePacket(CCharEntity* PChar) { ref(0x4A) = PChar->hookDelay; } + ref(0x4C) = PChar->StatusEffectContainer->m_Flags; // GEO bubble effects, changes bubble effect depending on what effect is activated. @@ -125,4 +130,9 @@ CCharUpdatePacket::CCharUpdatePacket(CCharEntity* PChar) ref(0x29) |= static_cast(PChar->StatusEffectContainer->GetStatusEffect(EFFECT_MOUNTED)->GetSubPower()); ref(0x5B) = PChar->StatusEffectContainer->GetStatusEffect(EFFECT_MOUNTED)->GetPower(); } + + if (PChar->m_PMonstrosity != nullptr) + { + ref(0x54) = monstrosity::GetPackedMonstrosityName(PChar); + } } diff --git a/src/map/packets/monipulator1.cpp b/src/map/packets/monipulator1.cpp index 53226c21b12..08f9553aec9 100644 --- a/src/map/packets/monipulator1.cpp +++ b/src/map/packets/monipulator1.cpp @@ -22,6 +22,7 @@ #include "common/socket.h" #include "monipulator1.h" +#include "utils/charutils.h" CMonipulatorPacket1::CMonipulatorPacket1(CCharEntity* PChar) { @@ -31,12 +32,19 @@ CMonipulatorPacket1::CMonipulatorPacket1(CCharEntity* PChar) ref(0x04) = 0x03; // Update Type ref(0x06) = 0xD8; // Variable Data Size - ref(0x08) = 0; // Species - ref(0x0A) = 0; // Flags? + ref(0x08) = (0xFCFE); // Species + ref(0x0A) = (0x0B45); // Flags? ref(0x0C) = 0; // Monstrosity Rank (0 = Mon, 1 = NM, 2 = HNM) - ref(0x12) = 0; // Infamy + ref(0x10) = (0x0074); + ref(0x12) = charutils::GetPoints(PChar, "infamy"); - std::memset(data + 0x1C, 0, 64); // Instinct Battlefield 1 - std::memset(data + 0x5C, 0, 128); // Monster Level Char Field + std::array instinct{0}; + + std::array levels{0}; + levels[1] = 0x01; + levels[18] = 0x01; + + std::memcpy(data + 0x1C, instinct.data(), 64); // Instinct Battlefield 1 + std::memcpy(data + 0x5C, levels.data(), 128); // Monster Level Char Field } diff --git a/src/map/packets/monipulator2.cpp b/src/map/packets/monipulator2.cpp index 05782b01e78..818bc36dcfe 100644 --- a/src/map/packets/monipulator2.cpp +++ b/src/map/packets/monipulator2.cpp @@ -32,4 +32,8 @@ CMonipulatorPacket2::CMonipulatorPacket2(CCharEntity* PChar) std::array packet2 = { 0x04, 0x00, 0xB0 }; memcpy(data + (0x04), &packet2, sizeof(packet2)); + + ref(0x86) = 0x0A; + + ref(0x88) = 0x3F; } diff --git a/src/map/packets/zone_in.cpp b/src/map/packets/zone_in.cpp index 3a45e95a472..22e6224a39a 100644 --- a/src/map/packets/zone_in.cpp +++ b/src/map/packets/zone_in.cpp @@ -118,7 +118,7 @@ CZoneInPacket::CZoneInPacket(CCharEntity* PChar, const EventInfo* currentEvent) this->setType(0x0A); this->setSize(0x104); - // It is necessary to work Manaklipper + // It is necessary to work Manaclipper // The last 8 bytes are similar for a while // unsigned char packet [] = { // 0x0D, 0x3A, 0x0C, 0x00, 0x11, 0x00, 0x19, 0x00, 0x02, 0xE4, 0x93, 0x10, 0x91, 0xE5, 0x93, 0x10}; // 0x2a = 0x10 @@ -130,18 +130,24 @@ CZoneInPacket::CZoneInPacket(CCharEntity* PChar, const EventInfo* currentEvent) ref(0x04) = PChar->id; ref(0x08) = PChar->targid; - memcpy(data + (0x84), PChar->GetName().c_str(), PChar->GetName().size()); + // 0x0A = Padding ref(0x0B) = PChar->loc.p.rotation; ref(0x0C) = PChar->loc.p.x; ref(0x10) = PChar->loc.p.y; ref(0x14) = PChar->loc.p.z; + // 0x18 = Run Count + + // 0x1A = Target Index + ref(0x1C) = PChar->GetSpeed(); ref(0x1D) = PChar->speedsub; ref(0x1E) = PChar->GetHPP(); ref(0x1F) = PChar->animation; + // 0x20 = Character Gender and Size + if (PChar->StatusEffectContainer->HasStatusEffect(EFFECT_MOUNTED)) { ref(0x20) = static_cast(PChar->StatusEffectContainer->GetStatusEffect(EFFECT_MOUNTED)->GetSubPower()); @@ -149,6 +155,10 @@ CZoneInPacket::CZoneInPacket(CCharEntity* PChar, const EventInfo* currentEvent) ref(0x21) = PChar->GetGender() * 128 + (1 << PChar->look.size); + ref(0x28) = 0x0100; // "Always 0x100" + + // 0x2A = Zone Animation + look_t* look = (PChar->getStyleLocked() ? &PChar->mainlook : &PChar->look); ref(0x44) = look->face; ref(0x45) = look->race; @@ -161,12 +171,6 @@ CZoneInPacket::CZoneInPacket(CCharEntity* PChar, const EventInfo* currentEvent) ref(0x52) = look->sub + 0x7000; ref(0x54) = look->ranged + 0x8000; - if (PChar->m_Monstrosity != 0) - { - ref(0x44) = PChar->m_Monstrosity; - ref(0x54) = 0xFFFF; - } - ref(0x56) = PChar->PInstance ? PChar->PInstance->GetBackgroundMusicDay() : PChar->loc.zone->GetBackgroundMusicDay(); ref(0x58) = PChar->PInstance ? PChar->PInstance->GetBackgroundMusicNight() : PChar->loc.zone->GetBackgroundMusicNight(); ref(0x5A) = PChar->PInstance ? PChar->PInstance->GetSoloBattleMusic() : PChar->loc.zone->GetSoloBattleMusic(); @@ -220,6 +224,9 @@ CZoneInPacket::CZoneInPacket(CCharEntity* PChar, const EventInfo* currentEvent) ref(0xAF) = PChar->loc.zone->CanUseMisc(MISC_MOGMENU); // flag allows you to use Mog Menu outside Mog House } + auto const& nameStr = PChar->GetName(); + std::memcpy(data + 0x84, nameStr.data(), nameStr.size()); + ref(0xA0) = PChar->GetPlayTime(); // time spent by the character in the game from the moment of creation ref(0xAE) = GetMogHouseLeavingFlag(PChar); @@ -249,4 +256,15 @@ CZoneInPacket::CZoneInPacket(CCharEntity* PChar, const EventInfo* currentEvent) ref(0xF8) = PChar->chatFilterFlags; ref(0x100) = 0x01; // observed: RoZ = 3, CoP = 5, ToAU = 9, WoTG = 11, SoA/original areas = 1 + + if (PChar->m_PMonstrosity != nullptr) + { + // TODO: These make the spawn in cleaner, but then the name doesn't work correctly + // ref(0x04) = PChar->m_PMonstrosity->Face; + // ref(0x05) = PChar->m_PMonstrosity->Race; + // ref(0x14) = 0xFFFF; + + // Enable Monstrosity menu options + ref(0x7E) = 0x1F; + } } diff --git a/src/map/zone.cpp b/src/map/zone.cpp index a8760573ea2..2de4ca596a9 100644 --- a/src/map/zone.cpp +++ b/src/map/zone.cpp @@ -40,6 +40,7 @@ #include "linkshell.h" #include "map.h" #include "message.h" +#include "monstrosity.h" #include "notoriety_container.h" #include "party.h" #include "spell.h" @@ -1095,6 +1096,8 @@ void CZone::CharZoneIn(CCharEntity* PChar) PChar->PLatentEffectContainer->CheckLatentsZone(); + monstrosity::HandleZoneIn(PChar); + charutils::ReadHistory(PChar); moduleutils::OnCharZoneIn(PChar);