Page 1 of 3

@mh

Posted: Mon Sep 14, 2015 6:49 pm
by uwill99
EDIT: With a lot of help from kjLotus (see following posts for stream of consciousness), this actually works.
I created a script to access my mog house anywhere in the world for the purpose of having an in-game menu for job changing.

Code: Select all

---------------------------------------------------------------------------------------------------
-- func: @mh
-- auth: 95% kjLotus and 5% uwill99 collab, bro
-- desc: opens the Mog House menu
---------------------------------------------------------------------------------------------------

cmdprops =
{
    permission = 0,
    parameters = ""
};

function onTrigger(player,npc)
    player:sendMenu(1);
end;
After we've made the GM command script, we need to alter our MySQL database. Go into your MySQL database, and run this query (I did it by hand, adding 32 to the value of the misc column of zone_settings which took forever)

Code: Select all

UPDATE zone_settings SET zone_misc = zone_misc & 0x40;
Start server and it should function properly. If it doesn't, then you need to alter the server code (I don't think you need to do this, though).

Do this if it doesn't work doing the stuff up above:

Amend the server code found in "packet_system.cpp", an easy way to find the section is to cntrl+F and find "Job Change". Two lines of code down you'll find:

Code: Select all

 if (PChar->loc.zone->CanUseMisc(MISC_MOGMENU) || PChar->m_moghouseID)


Delete it, save, and recompile.

Re: @mh

Posted: Mon Sep 14, 2015 6:52 pm
by kjLotus
The core server will check if you are in a mog house or not, or else you could just inject the mog house menu packet anywhere and change jobs whenever (which is a pretty big exploit)

Re: @mh

Posted: Mon Sep 14, 2015 7:35 pm
by uwill99
Awesome, kjLotus... I actually started thinking that was the problem, so I started trying to make my character seem as if it was in a moghouse even though it wasn't; since I don't know how to code I failed. Is there a way to figure out what packet to inject? My gameserver window keeps parsing "0B5" when I try to pull up the window, but the GM command @inject seems to work off of .dat files. I'm not concerned with exploits, since it's just a solo server and I'd be cheating myself out of fun. I'm trying to make it similar to the FFXIV playstyle where you switch a weapon and you switch jobs; the only improvement FFXIV made in the series IMHO.

Re: @mh

Posted: Mon Sep 14, 2015 7:44 pm
by kjLotus
Injecting will just do the same thing that @mh does - if you want it to work, you need to figure out where the mog house check is. Good way is to open up the menu, and then try to change jobs. When you try to change, the map server should get a packet (not B5, that one's chat), then go to that packet in packet_system.cpp and follow what it does, looking for "m_moghouseID"

Re: @mh

Posted: Mon Sep 14, 2015 8:27 pm
by uwill99
Thanks for the guidance, with your help I found it, in its very own section labeled "Job Change."

Code: Select all

/
************************************************************************
*                                                                       *
*  Job Change                                                           *
*                                                                       *
************************************************************************/

void SmallPacket0x100(map_session_data_t* session, CCharEntity* PChar, CBasicPacket data)
{
    if (PChar->loc.zone->CanUseMisc(MISC_MOGMENU) || PChar->m_moghouseID)
    {
        uint8 mjob = RBUFB(data, (0x04));
        uint8 sjob = RBUFB(data, (0x05));

        if ((mjob > 0x00) && (mjob < MAX_JOBTYPE) && (PChar->jobs.unlocked & (1 << mjob)))
        {
            JOBTYPE prevjob = PChar->GetMJob();
            PChar->resetPetZoningInfo();

            charutils::RemoveAllEquipment(PChar);
            PChar->SetMJob(mjob);
            PChar->SetMLevel(PChar->jobs.job[PChar->GetMJob()]);
            PChar->SetSLevel(PChar->jobs.job[PChar->GetSJob()]);

            // If removing RemoveAllEquipment, please add a charutils::CheckUnarmedItem(PChar) if main hand is empty.
            puppetutils::LoadAutomaton(PChar);
            if (mjob == JOB_BLU)
            {
                blueutils::LoadSetSpells(PChar);
            }
            else if (prevjob == JOB_BLU)
            {
                blueutils::UnequipAllBlueSpells(PChar);
            }
        }

        if ((sjob > 0x00) && (sjob < MAX_JOBTYPE) && (PChar->jobs.unlocked & (1 << sjob)))
        {
            JOBTYPE prevsjob = PChar->GetSJob();

            PChar->SetSJob(sjob);
            PChar->SetSLevel(PChar->jobs.job[PChar->GetSJob()]);

            charutils::CheckEquipLogic(PChar, SCRIPT_CHANGESJOB, prevsjob);
            puppetutils::LoadAutomaton(PChar);
            if (sjob == JOB_BLU)
                blueutils::LoadSetSpells(PChar);
            else if (prevsjob == JOB_BLU)
                blueutils::UnequipAllBlueSpells(PChar);

            uint16 subType = PChar->m_Weapons[SLOT_SUB]->getDmgType();

            if (subType > 0 && subType < 4)
            {
                charutils::UnequipItem(PChar, SLOT_SUB);
            }

        }
        luautils::CheckForGearSet(PChar); // check for gear set on gear change

        charutils::BuildingCharSkillsTable(PChar);
        charutils::CalculateStats(PChar);
        charutils::BuildingCharTraitsTable(PChar);
        PChar->PRecastContainer->ResetAbilities();
        charutils::BuildingCharAbilityTable(PChar);
        charutils::BuildingCharWeaponSkills(PChar);

        PChar->StatusEffectContainer->DelStatusEffectsByFlag(EFFECTFLAG_DISPELABLE);

        PChar->ForParty([](CBattleEntity* PMember)
        {
            ((CCharEntity*)PMember)->PLatentEffectContainer->CheckLatentsPartyJobs();
        });


        PChar->UpdateHealth();

        PChar->health.hp = PChar->GetMaxHP();
        PChar->health.mp = PChar->GetMaxMP();

        charutils::SaveCharStats(PChar);

        PChar->pushPacket(new CCharJobsPacket(PChar));
        PChar->pushPacket(new CCharUpdatePacket(PChar));
        PChar->pushPacket(new CCharHealthPacket(PChar));
        PChar->pushPacket(new CCharStatsPacket(PChar));
        PChar->pushPacket(new CCharSkillsPacket(PChar));
        PChar->pushPacket(new CCharRecastPacket(PChar));
        PChar->pushPacket(new CCharAbilitiesPacket(PChar));
        PChar->pushPacket(new CCharJobExtraPacket(PChar, true));
        PChar->pushPacket(new CCharJobExtraPacket(PChar, false));
        PChar->pushPacket(new CMenuMeritPacket(PChar));
        PChar->pushPacket(new CCharSyncPacket(PChar));
    }
    return;
}
But to me, it doesn't look like it exactly tells you what the Mog House Packet is. I took what you told me and searched the boards and found this data:

Code: Select all

       
WBUFW(data,(0xAA)-4) = GetMogHouseID(PChar);            // Mog House id
WBUFB(data,(0xAE)-4) = GetMogHouseFlag(PChar);          // Mog House leaving flag
I did @inject 0xAA and nothing changed.

Re: @mh

Posted: Mon Sep 14, 2015 9:05 pm
by uwill99
Yeah. I seem out of my element for now. I saw a post concerning a .dat file someone made for Aht Urghan. I'll have to dig a bit deeper, but I did find the Packet IDs from the DSP Wiki which has Menu Mog House listed as - 0x002E, which I did not find myself in the packet_system.cpp

Re: @mh

Posted: Mon Sep 14, 2015 9:16 pm
by kjLotus
I think I have confused you (or you me). Why are you trying to use @inject?

Re: @mh

Posted: Mon Sep 14, 2015 9:38 pm
by uwill99
Haha, yeah I probably confused you, sorry. I guess I was trying to make a GM command that would allow Mog House job changes anywhere in the world using the Mog House Menu system (like how you can bring up the AH menu.) Your suggestion of injecting the Mog House packet to my client was brilliant, but I couldn't seem to do it. I know just enough to get turned around. I now know the @inject function has to work with a .dat file in hexadecimal form... I gleaned that from reading costume stuff on the forums, but any information outside of that is pretty scant. I've learned as much as I have from either you or teotwawki, copying examples in .luas, and fiddling around in Navicat, haha. The Packet IDs on the DSP WIki has the Menu Mog House listed as (0x002E - Menu Mog House.) This may not be the information you were leading me toward, but I couldn't find a real clear cut example in packet_system.cpp around any packets sent to my gameserver where m_moghouseID is defined except here:

Code: Select all

if (PChar->loc.zone->CanUseMisc(MISC_MOGMENU) || PChar->m_moghouseID)
    {
        uint8 mjob = RBUFB(data, (0x04));
        uint8 sjob = RBUFB(data, (0x05));
...
Anyway, thanks for the help so far, if you are bored I could use the help, but I know this is a pretty low priority thing.

Re: @mh

Posted: Mon Sep 14, 2015 9:46 pm
by kjLotus
using inject is the same as using @mh - it specifically does not work because that would be an exploit.

anyways, the code blurb you pasted is exactly what you should be looking for for allowing your @mh command to change jobs. It reads "if the zone has the mog house menu (ie. zones with nomad moogles) or the character is inside a mog house". So if you want it to work everywhere you can just remove that if statement

Re: @mh

Posted: Mon Sep 14, 2015 10:05 pm
by uwill99
Oh! I see, I misunderstood your comment about using inject. Thanks for the help kjLotus! And thanks for translating that code fragment, I took some logic classes in college which have helped with some of the code but it's hard >for me< to isolate individual parts of an argument.