EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Development: Custom Code (https://www.eqemulator.org/forums/forumdisplay.php?f=665)
-   -   Changing the level-based class prefixes in /who (https://www.eqemulator.org/forums/showthread.php?t=38825)

zerjz3 09-24-2014 12:00 AM

Changing the level-based class prefixes in /who
 
My goal is to change this part of classes.cpp:

Code:

const char* GetEQClassName(uint8 class_, uint8 level) {
        switch(class_) {
                case WARRIOR:
                        if (level >= 70)
                                return "Vanquisher";
                        else if (level >= 65)
                                return "Overlord"; //Baron-Sprite: LEAVE MY CLASSES ALONE.
                        else if (level >= 60)
                                return "Warlord";
                        else if (level >= 55)
                                return "Myrmidon";
                        else if (level >= 51)
                                return "Champion";
                        else
                                return "Warrior";

to something that checks for the player either having a certain flag, or having a certain item in their inventory. Is this at all possible?

Drajor 09-24-2014 01:41 AM

The client decides what text to print based on a class number in the who response. Name and Guild name are the only server-side changeable fields I am aware of. You could try messing with the rankmessage field (Gives GM/Trader additional text in who results). Worth playing around with for sure!

jdoran 09-24-2014 02:05 AM

Edit: Drajor posted while I was writing the following. I didn't know that /who was done client-side. But perhaps zerjz3 wanted to change that function for some other reason? I'm reaching.

You would need to change the if statements to something more complicated. The problem is that GetEQClassName() currently depends only on class and level. You would need to add another parameter to the function.

Now the easiest way to do this is place the new parameter at the end, and assign a default value. However... GetEQClassName already has an optional parameter: level. You could require a level be passed everywhere you want the new titles, or for about the same amount of work you could just pass in a new parameter. A pointer to a Client would seem a reasonable choice.

That isn't such a tough problem. We can (under Linux) use find and grep to search for usage. Visual Studio can do the same thing under Windows. Now while there are advanced regular expressions in grep, I'm lazy and like to stick with the simple stuff. So, in your eqemu directory:

find . -exec grep GetEQClassName {} /dev/null \; 2> /dev/null | grep -v Binary

give us:

Code:

./common/classes.h:const char* GetEQClassName(uint8 class_, uint8 level = 0);
./common/classes.cpp:const char* GetEQClassName(uint8 class_, uint8 level) {
./zone/embparser.cpp:          ExportVar(package_name.c_str(), "class", GetEQClassName(mob->GetClass()));
./zone/client.cpp:      Message(0,"Your target is a level %i %s. It appears %s and %s for its level. It seems %s",who->GetLevel(),GetEQClassName(who->GetClass(),1),dmg,hitpoints,resists);
./zone/bot.cpp:        GetBotOwner()->Message(15, "A %s - %s bot was detected. Is this Race/Class combination allowed?.", GetRaceName(GetRace()), GetEQClassName(GetClass(), GetLevel()));
./world/client.cpp:    clog(WORLD__CLIENT,"Name approval request. Name=%s, race=%s, class=%s",char_name,GetRaceName(race),GetEQClassName(clas));
./world/clientlist.cpp:                                sprintf(line, "  %s[RolePlay %i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetEQClassName(cle->class_(),cle->level()), cle->name(), GetRaceName(cle->race()), tmpguild, tmpZone, LFG, accinfo);
./world/clientlist.cpp:                                sprintf(line, "  %s[ANON %i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetEQClassName(cle->class_(),cle->level()), cle->name(), GetRaceName(cle->race()), tmpguild, tmpZone, LFG, accinfo);
./world/clientlist.cpp:                        sprintf(line, "  %s[%i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetEQClassName(cle->class_(),cle->level()), cle->name(), GetRaceName(cle->race()), tmpguild, tmpZone, LFG, accinfo);
./world/eqw.cpp:        res["class"] = GetEQClassName(cle->class_());

There are 7 calls to this function. Easily fixed. If you don't have a pointer to the Client handy, pass in a NULL and revert to the default behavior. It is late, and this is off the top of my head:

Code:

if ((level >= 70)
{
    if ((client) && (client -> GetInv().HasItem(itemID, 0, 0xff)))
    {
            return "UberWarlord";
    }
    else
    {
            return "Warlord";
    }
}


Drajor 09-24-2014 02:06 AM

I just tested this quickly, you can use strings from eqstr_us.txt for rank.
My level 1 cleric was listed as;
High Priest[1 Cleric] Daaxodush (Human).

Pretty neat.

zerjz3 09-24-2014 07:13 AM

Quote:

Originally Posted by Drajor (Post 234165)
I just tested this quickly, you can use strings from eqstr_us.txt for rank.
My level 1 cleric was listed as;
High Priest[1 Cleric] Daaxodush (Human).

Pretty neat.

How exactly did you go about this? I know that the names of the ranks can be edited in eqstr_us.txt , but if I wanted to have two available rank titles for each class, how would I execute this?

Did you use the method written out by jdoran to do this or did you simply edit something in eqstr_us.txt? I tried adding this code

Code:

if ((level >= 70)
{
    if ((client) && (client -> GetInv().HasItem(itemID, 0, 0xff)))
    {
            return "UberWarlord";
    }
    else
    {
            return "Warlord";
    }
}

to classes.cpp and compiling, but there were many errors when trying to compile.

Looking for just a little more hand holding here, as I think it seems like this is possible based on what you guys are saying, but just not exactly sure how to execute it yet.


Edit: These are the three errors I get when trying to compile:

Code:

Error        1        error C2065: 'client' : undeclared identifier        C:\EQ\Source\common\classes.cpp        24        1        common
Error        2        error C2227: left of '->GetInv' must point to class/struct/union/generic type        C:\EQ\Source\common\classes.cpp        24        1        common
Error        3        error C2228: left of '.HasItem' must have class/struct/union        C:\EQ\Source\common\classes.cpp        24        1        common


Drajor 09-24-2014 07:39 AM

Quote:

Did you use the method written out by jdoran to do this or did you simply edit something in eqstr_us.txt? I tried adding this code
Neither. See EntityList::zoneWho, specifically;
Code:

if (ClientEntry->IsTrader())
        WAPP2->RankMSGID = 12315;
else if (ClientEntry->IsBuyer())
        WAPP2->RankMSGID = 6056;
else if (ClientEntry->Admin() >= 10)
        WAPP2->RankMSGID = 12312;
else
        WAPP2->RankMSGID = 0xFFFFFFFF;

The RankMSGID corresponds to a string ID from eqstr_us.txt. You could add more conditions there for detecting an item or whatever. If you check the hard coded IDs currently in use you find;

12315 TRADER
6056 BUYER
12312 * GM *

Based on my limited tests you can use any valid string ID. Note that this only applies to local zone who, not who all which happens in different place.

zerjz3 09-24-2014 07:59 AM

Awesome, drajor! I've got this working in its natural form. Now, I just need to find the condition to check if a player has an item. I could actually really use an example of that if you don't mind helping me out just a bit more. I've searched around but everything I've found deals with checking items in quest scripts but not in the source code

Drajor 09-24-2014 08:20 AM

Quick and nasty;
Code:

if (ClientEntry->IsTrader())
        WAPP2->RankMSGID = 12315;
else if (ClientEntry->IsBuyer())
        WAPP2->RankMSGID = 6056;
else if (ClientEntry->Admin() >= 10)
        WAPP2->RankMSGID = 12312;
else if (ClientEntry->GetInv()->HasItem(20542) > -1)
        WAPP2->RankMSGID = 8043;

else
        WAPP2->RankMSGID = 0xFFFFFFFF;

This (should) check whether that character has item 20542(Singing Short Sword) and change their /who output to have Lyricist prefix.. e.g.

Lyricist[1 Bard] Drajor (Barbarian)

zerjz3 09-24-2014 08:25 AM

Code:

Error        10        error C2819: type 'Inventory' does not have an overloaded member 'operator ->'        C:\EQ\Source\zone\entity.cpp        4076        1        zone
Error        11        error C2232: '->Inventory::HasItem' : left operand has 'class' type, use '.'        C:\EQ\Source\zone\entity.cpp        4076        1        zone

I get these errors when compiling with that code... seems like we're getting really close to having this figured out.. I copy/pasted what you posted, checking now to make sure I didn't leave some ; or something out from being sloppy

Edit:
Code:

            else if (ClientEntry->GetInv().HasItem(17181, 0, 0xff))
                    WAPP2->RankMSGID = 8043;

compiled successfully, testing now...

Edit: Everything compiles successfully, the server runs without error, but having the specified item doesn't return any sort of string before the level and class in /who ... experimenting more with this

zerjz3 09-24-2014 08:51 AM

Writing it as such

Code:

            else if (ClientEntry->GetInv().HasItem(17181) > -1)
                    WAPP2->RankMSGID = 1504;

compiles but doesn't show anything in-game.

Drajor 09-24-2014 09:00 AM

What client are you using?

zerjz3 09-24-2014 09:03 AM

Quote:

Originally Posted by Drajor (Post 234174)
What client are you using?



I'm on the Titanium client... only client I have atm

Drajor 09-24-2014 09:10 AM

I am fairly certain that anything below SoF handles /who client side :( I recommend Underfoot for everything except P99.

zerjz3 09-24-2014 09:11 AM

Ok, I will get a copy of Underfoot and report back in this thread with my findings.

zerjz3 10-13-2014 04:15 PM

Update: I can confirm now with the Underfoot client that this method works for the intended purpose. Thanks for the help!


All times are GMT -4. The time now is 12:26 AM.

Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.