Page 1 of 1

Adding support for EXP items

PostPosted: Fri May 30, 2008 3:45 pm
by PurpleYouko
here is the code you need to be able to support EXP rate items in your server.
This will be included in the SVN at some point once we are settled into our new project properly and once Drakia and i get the darn skills working properly.
In the mean time, if you want to add this support to osirose or osprose servers (osrose is slightly different + Lmame has already coded it for rev 81) then here it is.

It is pretty basic code but it is spread all over the server so follow carefully.
Some parts are optional but they will be included in a second post.

in chartypes.h, find
  1. unsigned int MaxSummonGauge;
  2.     unsigned int MPReduction;
  3.     unsigned int ExtraDamage;

after, add

This adds a personal xprate multiplier value to your player->stats structure.

in Character.h, find
  1. virtual unsigned int GetDefense( );

after, add
  1. virtual unsigned int GetXPRate( );


in charstats.cpp, find
  1. // virtual [return defense]
  2. unsigned int CCharacter::GetDefense( )
  3. {
  4.     return 0;
  5. }

after, add
  1. // virtual [return xprate]
  2. unsigned int CCharacter::GetXPRate( )
  3. {
  4.     return 0;        
  5. }


in WorldMonster.h, find
  1. unsigned int GetDefense( );

after, add
  1. unsigned int GetXPRate( );


in monsterstats.cpp, find
  1. unsigned int CMonster::GetCritical( )
  2. {
  3.     return 60;  //60 = 20% of 300 our critical probability
  4. }

after, add
  1. unsigned int CMonster::GetXPRate( )
  2. {
  3.     return 0;        
  4. }

Why does a monster need xprate?
it doesn't but the monster and character classes are intricately interwoven and the server will not compile properly unless you add it.

still in monsterstats.cpp, find
  1. Stats->Defense = GetDefense( );

after, add
  1. Stats->xprate = GetXPRate( );


in player.h, find
  1. unsigned int GetDefense( );

after, add
  1. unsigned int GetXPRate( );


in Playerdata.cpp, find
  1. Clan->clanid = atoi(row[26]);
  2.     Clan->clanrank = atoi(row[27]);
  3.     Position->saved = atoi(row[28]);

after, add
  1. Stats->xprate = GetXPRate();


in playerstats.cpp
add this function anywhere you like.
You might as well put it after the one that returns defence just to keep it neat.
  1. // Return XPRate
  2. unsigned int CPlayer::GetXPRate( )
  3. {
  4.     UINT XPRate = 0;
  5.     for(UINT i=1;i<12;i++)
  6.     {
  7.         if( items[i].count != 0 )
  8.         {
  9.             if(items[i].itemtype>9)
  10.             {
  11.                 Log(MSG_WARNING, "Char %s have equip invalid item: %i,%i", CharInfo->charname, items[i].itemtype, items[i].itemnum );
  12.                 continue;
  13.             }            
  14.             if( GServer->EquipList[items[i].itemtype].Index[items[i].itemnum]->stat1[0] == XP_RATE)
  15.             {
  16.                 XPRate += GServer->EquipList[items[i].itemtype].Index[items[i].itemnum]->stat1[1];
  17.                 //Log( MSG_INFO, "XP rate item detected basic stat = %i item number %i", GServer->EquipList[items[i].itemtype].Index[items[i].itemnum]->stat1[1],items[i].itemnum);
  18.                
  19.             }
  20.             if( GServer->EquipList[items[i].itemtype].Index[items[i].itemnum]->stat2[0] == XP_RATE)
  21.             {
  22.                 XPRate += GServer->EquipList[items[i].itemtype].Index[items[i].itemnum]->stat2[1];
  23.                 //Log( MSG_INFO, "XP rate item detected basic stat = %i item number %i", GServer->EquipList[items[i].itemtype].Index[items[i].itemnum]->stat1[2],items[i].itemnum);
  24.                    
  25.             }
  26.             if(items[i].stats>0 && items[i].stats<500)
  27.             {
  28.                 if(GServer->StatsList[items[i].stats].stat[0] == XP_RATE)
  29.                 {
  30.                     XPRate += GServer->StatsList[items[i].stats].value[0];
  31.                     //Log( MSG_INFO, "XP rate item detected. extra stat = %i item number %i", GServer->StatsList[items[i].stats].value[0],items[i].itemnum);
  32.                        
  33.                 }
  34.                 if(GServer->StatsList[items[i].stats].stat[1] == XP_RATE)
  35.                 {
  36.                     XPRate += GServer->StatsList[items[i].stats].value[1];
  37.                     //Log( MSG_INFO, "XP rate item detected. extra stat = %i item number %i", GServer->StatsList[items[i].stats].value[1],items[i].itemnum);
  38.                    
  39.                 }
  40.             }            
  41.         }
  42.     }
  43.     //Log( MSG_INFO, "XP rate rate calculated as = %i", XPRate);
  44.     if(XPRate < 1)
  45.         XPRate=1;
  46.     return XPRate;        
  47. }

 
still in playerstats.cpp, find
  1. Stats->Defense = GetDefense( );

after, add
  1. Stats->xprate = GetXPRate( );

 
in worldprocesses.cpp, find
  1. thisclient->CharInfo->Exp +=  GetColorExp( thisclient->Stats->Level, thismon->thisnpc->level, exp )

The entire line may be slightly different. i don't have an unmodified version to check against. Either way it should be easy enough to find it.
replace line with
  1. thisclient->CharInfo->Exp +=  GetColorExp( thisclient->Stats->Level, thismon->thisnpc->level, exp ) * thisclient->Stats->xprate;

 
in the same function, find
  1. partyclient->CharInfo->Exp +=  GetColorExp( partyclient->Stats->Level, thismon->Stats->Level, (UINT)round(thisparty->exp / thisparty->num) )

Again this may be slightly different but easy to find.
replace line with
  1. partyclient->CharInfo->Exp +=  GetColorExp( partyclient->Stats->Level, thismon->Stats->Level, (UINT)round(thisparty->exp / thisparty->num) ) * partyclient->Stats->xprate;

 
same function, about 3 lines after teh last change, find
  1. partyclient->CharInfo->Exp +=  GetColorExp( partyclient->Stats->Level, thismon->Stats->Level, (UINT)round(partyclient->Stats->Level * thisparty->exp / thisparty->maxlevel) )

replace line with
  1. partyclient->CharInfo->Exp +=  GetColorExp( partyclient->Stats->Level, thismon->Stats->Level, (UINT)round(partyclient->Stats->Level * thisparty->exp / thisparty->maxlevel) ) * partyclient->Stats->xprate;

 
and finally a little addition to datatypes.h so that the function in playerstats knows what value to look far.
find

after, add


That should be all you need to be able to read back the XP rate of items such as hero medals and so on.

Re: Adding support for EXP items

PostPosted: Fri May 30, 2008 3:53 pm
by PurpleYouko
The optional stuff now.
This isn't strictly necessary to make the xprate mod work but may be useful to debug it if it doesn't.
It also adds a log of useful readbacks to your server under a new custom command structure.

somewhere in gmcmds.cpp, pakGMCommand( CPlayer* thisclient, CPacket* P ) function, add this conditional.
Doesn't matter where as long as it follows the common structure of the function
  1.  
  2. else if(strcmp(command, "mystat")==0)
  3.     {
  4.          if ((tmp = strtok(NULL, " "))==NULL)return true;
  5.          if(strcmp(tmp, "ap")==0)
  6.          {
  7.              char buffer2[200];
  8.              sprintf ( buffer2, "My Attack Power is %i", thisclient->Stats->Attack_Power );
  9.              SendPM(thisclient, buffer2);
  10.          }
  11.          else if(strcmp(tmp, "acc")==0)
  12.          {
  13.              char buffer2[200];
  14.              sprintf ( buffer2, "My Accuracy is %i", thisclient->Stats->Accury );
  15.              SendPM(thisclient, buffer2);
  16.          }
  17.          else if(strcmp(tmp, "hp")==0)
  18.          {
  19.              char buffer2[200];
  20.              sprintf ( buffer2, "My current HP is %i", thisclient->Stats->HP );
  21.              SendPM(thisclient, buffer2);
  22.          }
  23.          else if(strcmp(tmp, "mp")==0)
  24.          {
  25.              char buffer2[200];
  26.              sprintf ( buffer2, "My current MP is %i", thisclient->Stats->MP );
  27.              SendPM(thisclient, buffer2);
  28.          }
  29.          else if(strcmp(tmp, "maxhp")==0)
  30.          {
  31.              char buffer2[200];
  32.              sprintf ( buffer2, "My Maximum HP is %i", thisclient->GetMaxHP());
  33.              SendPM(thisclient, buffer2);
  34.          }
  35.          else if(strcmp(tmp, "maxmp")==0)
  36.          {
  37.              char buffer2[200];
  38.              sprintf ( buffer2, "My maximum MP is %i", thisclient->GetMaxMP());
  39.              SendPM(thisclient, buffer2);
  40.          }
  41.          else if(strcmp(tmp, "dodge")==0)
  42.          {
  43.              char buffer2[200];
  44.              sprintf ( buffer2, "My dodge is %i", thisclient->Stats->Dodge);
  45.              SendPM(thisclient, buffer2);  
  46.          }
  47.          else if(strcmp(tmp, "def")==0)
  48.          {
  49.              char buffer2[200];
  50.              sprintf ( buffer2, "My defense is %i", thisclient->Stats->Defense);
  51.              SendPM(thisclient, buffer2);  
  52.          }
  53.          else if(strcmp(tmp, "mdef")==0)
  54.          {
  55.              char buffer2[200];
  56.              sprintf ( buffer2, "My Magic defense is %i", thisclient->Stats->Magic_Defense);
  57.              SendPM(thisclient, buffer2);  
  58.          }
  59.          else if(strcmp(tmp, "crit")==0)
  60.          {
  61.              char buffer2[200];
  62.              sprintf ( buffer2, "My critical is %i", thisclient->Stats->Critical);
  63.              SendPM(thisclient, buffer2);  
  64.          }
  65.          else if(strcmp(tmp, "mspd")==0)
  66.          {
  67.              char buffer2[200];
  68.              sprintf ( buffer2, "My move speed is %i", thisclient->Stats->Move_Speed);
  69.              SendPM(thisclient, buffer2);  
  70.          }
  71.          else if(strcmp(tmp, "aspd")==0)
  72.          {
  73.              char buffer2[200];
  74.              sprintf ( buffer2, "My attack speed is %i", thisclient->Stats->Attack_Speed);
  75.              SendPM(thisclient, buffer2);  
  76.          }
  77.          else if(strcmp(tmp, "xprate")==0)
  78.          {
  79.              char buffer2[200];
  80.              sprintf ( buffer2, "My xp rate is %i", thisclient->Stats->xprate);
  81.              SendPM(thisclient, buffer2);    
  82.          }
  83.     }

This will add all kinds of feedback so that you can easily compare stats from server side to client side.
use this structure /mystat xprate to read back your current server side XPrate
or /mystat mspd to find out what the server currently calculates your move speed to be.

If you add this without adding the xprate mod in the previous post then you will need to comment out or remove this section
  1. else if(strcmp(tmp, "xprate")==0)
  2.          {
  3.              char buffer2[200];
  4.              sprintf ( buffer2, "My xp rate is %i", thisclient->Stats->xprate);
  5.              SendPM(thisclient, buffer2);    
  6.          }

otherwise you will get compile errors.