Files
ROSS/Src/World Server/worldpackets.cpp
T
ThomasandClaude Sonnet 5 560f6a968f Rebrand welcome messages and re-enable drop-roll debug logging
Welcome message default/example changed from "Welcome to ROSE" to
"Welcome to ROSS", and the hardcoded post-login system message
replaced with a ROSS-specific credit line.

Also re-enable the codedebug SendPM lines in GetNewDrop that report
the raw randv/money/zulyrate/item/itemrate values behind each
zuly-vs-item roll (previously commented out) -- needed to diagnose
in-game why item drops are still rare/absent after the drop-rate and
item-index fixes, without guessing at STB drop-table values blind.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-09 07:16:01 +02:00

4599 lines
178 KiB
C++

/*
Rose Online Server Emulator
Copyright (C) 2006,2007 OSRose Team http://www.osrose.net
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 2
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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
developed with Main erose/hrose source server + some change from the original eich source
*/
#include "worldserver.h"
// Send Characters information
void CWorldServer::pakPlayer( CPlayer *thisclient )
{
unsigned cbyte = 0;
CRespawnPoint* thisrespawn = GetRespawnByID( thisclient->Position->respawn );
if(thisclient->Position->saved == 20&&thisrespawn->destMap!=20)
thisclient->Position->saved = 22;
if(thisrespawn != NULL)
{
thisclient->Position->destiny = thisrespawn->dest;
thisclient->Position->current = thisclient->Position->destiny;
//Log(MSG_DEBUG,"(pakPlayer) Destiny and current set to X: %f Y: %f.",thisclient->Position->current.x,thisclient->Position->current.y);
thisclient->Position->Map = thisrespawn->destMap;
}
else
{
thisclient->Position->destiny.x = 5300;
thisclient->Position->destiny.y = 5200;
thisclient->Position->current = thisclient->Position->destiny;
thisclient->Position->Map = 1;
}
CMap* map = MapList.Index[thisclient->Position->Map];
map->AddPlayer( thisclient );
BEGINPACKET(pak, 0x715);
ADDBYTE( pak, thisclient->CharInfo->Sex ); // Sex
ADDWORD( pak, thisclient->Position->Map ); // Map
ADDFLOAT( pak, thisclient->Position->current.x*100 ); // Pos X
ADDFLOAT( pak, thisclient->Position->current.y*100 ); // Pos Y
ADDWORD( pak, thisclient->Position->saved );
ADDDWORD( pak, thisclient->CharInfo->Face ); // Face
ADDDWORD( pak, thisclient->CharInfo->Hair ); // Hair
ADDDWORD( pak, BuildItemShow(thisclient->items[2]) ); // Cap
ADDDWORD( pak, BuildItemShow(thisclient->items[3]) ); // Body
ADDDWORD( pak, BuildItemShow(thisclient->items[5]) ); // Gloves
ADDDWORD( pak, BuildItemShow(thisclient->items[6]) ); // Boots
ADDDWORD( pak, BuildItemShow(thisclient->items[1]) ); // Face
ADDDWORD( pak, BuildItemShow(thisclient->items[4]) ); // Back
ADDDWORD( pak, BuildItemShow(thisclient->items[7]) ); // Weapon
ADDDWORD( pak, BuildItemShow(thisclient->items[8]) ); // SubWeapon
ADDBYTE( pak, 0x01 ); // Birth Stone
ADDBYTE( pak, 0x00 );
ADDBYTE( pak, 0x00 );
ADDWORD( pak, thisclient->CharInfo->Job ); // Job
ADDBYTE( pak, thisclient->Union_s->unionvar[0]); // Union Variable [0]
ADDBYTE( pak, 0x00 ); //rank
ADDBYTE( pak, 0x00 ); //fame
ADDWORD( pak, thisclient->Attr->Str ); // Str
ADDWORD( pak, thisclient->Attr->Dex ); // Dex
ADDWORD( pak, thisclient->Attr->Int ); // Int
ADDWORD( pak, thisclient->Attr->Con ); // Con
ADDWORD( pak, thisclient->Attr->Cha ); // Cha
ADDWORD( pak, thisclient->Attr->Sen ); // Sen
ADDWORD( pak, thisclient->Stats->HP ); // Current HP
ADDWORD( pak, thisclient->Stats->MP ); // Current MP
ADDWORD( pak, thisclient->CharInfo->Exp ); // Exp
ADDWORD( pak, 0x0000 );
ADDWORD( pak, thisclient->Stats->Level ); // Level
ADDWORD( pak, thisclient->CharInfo->StatPoints ); // Stat Points
ADDWORD( pak, thisclient->CharInfo->SkillPoints ); // Skill Points
ADDBYTE( pak, 0x64 ); // Body Size
ADDBYTE( pak, 0x64 ); // Head Size
ADDWORD( pak, 0x0000 );
ADDWORD( pak, 0x0000 );
ADDWORD( pak, 0x0000 );
ADDWORD( pak, 0x0000 );
ADDWORD( pak, thisclient->Union_s->unionvar[1] );//union points Junon Order
ADDWORD( pak, thisclient->Union_s->unionvar[2] );//union points
ADDWORD( pak, thisclient->Union_s->unionvar[3] );//union points
ADDWORD( pak, thisclient->Union_s->unionvar[4] );//union points
ADDWORD( pak, thisclient->Union_s->unionvar[5] );//union points
ADDWORD( pak, thisclient->Union_s->unionvar[6] );//union points
ADDWORD( pak, thisclient->Union_s->unionvar[7] );//union points
ADDWORD( pak, thisclient->Union_s->unionvar[8] );//union points
ADDWORD( pak, thisclient->Union_s->unionvar[9] );//union points
ADDWORD( pak, thisclient->Union_s->unionvar[10] );//union point
ADDWORD( pak, 0x0000 );
ADDWORD( pak, 0x0000 );
ADDWORD( pak, 0x0000 );
ADDWORD( pak, 0x0000 );
ADDBYTE( pak, 0x00 );
ADDWORD( pak, thisclient->CharInfo->stamina ); // Stamina
for(short i=0; i<326; i++)
ADDBYTE( pak, 0x00 );
for (char i=0; i<30; i++)
ADDWORD( pak, thisclient->bskills[i] );//Basic skills
for (char i=0; i<30; i++)
ADDWORD( pak, thisclient->askill[i]+thisclient->askilllvl[i] );//Active skills
for (char i=0; i<30; i++)
ADDWORD( pak, thisclient->pskill[i]+thisclient->pskilllvl[i] );//Passive skills
for(short i=0; i<60; i++)//unused ????
ADDBYTE( pak, 0 );
for (char i=0; i<32; i++)
ADDWORD( pak, thisclient->quickbar[i] ); // QUICKBAR ROW 1 STARTS
ADDWORD( pak, thisclient->CharInfo->charid );
ADDWORD( pak, 0x00 );
for(unsigned j = 0; j < strlen(thisclient->CharInfo->charname); j++)
{
ADDBYTE(pak, thisclient->CharInfo->charname[j] );
}
ADDBYTE( pak, 0x00 );
ADDBYTE( pak, 0x00 );
thisclient->client->SendPacket( &pak );
}
// Send Inventory Information
void CWorldServer::pakInventory( CPlayer *thisclient )
{
unsigned cbyte=0;
STARTPACKET(pak, 0x716, 854 );
SETQWORD( pak, 0x000, thisclient->CharInfo->Zulies );
cbyte += 8;
for(unsigned j=0; j<140; j++)
{
//Log(MSG_INFO,"slot: %i itemid: %i type: %i count: %i",j, thisclient->items[j].itemnum,thisclient->items[j].itemtype,thisclient->items[j].count);
SETWORD( pak, cbyte+0, BuildItemHead( thisclient->items[j] ) );
SETDWORD( pak, cbyte+2, BuildItemData( thisclient->items[j] ) );
cbyte += 6;
}
cbyte-= 6;
thisclient->client->SendPacket( &pak );
}
// Send Quest information
void CWorldServer::pakQuestData( CPlayer *thisclient )
{
//Log( MSG_DEBUG, "Starting pakQuestData");
CPacket pakout;
//Log( MSG_DEBUG, "creating packet");
pakout.StartPacket( 0x71b );
//Log( MSG_DEBUG, "Starting packet");
for(dword i = 0; i < 5; i++) pakout.AddWord(thisclient->quest.EpisodeVar[i]);
//Log( MSG_DEBUG, "added episode vars");
for(dword i = 0; i < 3; i++) pakout.AddWord(thisclient->quest.JobVar[i]);
//Log( MSG_DEBUG, "added job vars");
for(dword i = 0; i < 7; i++) pakout.AddWord(thisclient->quest.PlanetVar[i]);
//Log( MSG_DEBUG, "added planet vars");
for(dword i = 0; i < 10; i++) pakout.AddWord(thisclient->quest.UnionVar[i]);
//Log( MSG_DEBUG, "added union vars");
for( unsigned i = 0; i < 10; i++ )
{
//Log( MSG_DEBUG, "starting main loop %i",i);
pakout.AddWord( thisclient->quest.quests[i].QuestID );
//Log( MSG_DEBUG, "added quest ID");
long int Time = 0;
//Log( MSG_DEBUG, "Initialized Time");
//Log( MSG_DEBUG, "This Quest quest id = %i",thisclient->quest.quests[i].QuestID);
//Log( MSG_DEBUG, "This Quest STB quest id = %i",STB_QUEST.rows[thisclient->quest.quests[i].QuestID][1]);
if (thisclient->quest.quests[i].QuestID > 0 && thisclient->quest.quests[i].QuestID < STB_QUEST.rowcount && STB_QUEST.rows[thisclient->quest.quests[i].QuestID][1] > 0)
{
//Log( MSG_DEBUG, "client has a timed quest");
Time += thisclient->quest.quests[i].StartTime; // Start time
Time += STB_QUEST.rows[thisclient->quest.quests[i].QuestID][1] * 10; // Time to finish
Time -= time(NULL); // Current time
if (Time < 0) Time = 0; // Time is up
Time /= 10; // Divide to get 10's of seconds
//Log( MSG_DEBUG, "Timed variables set %i",Time);
}
//Log( MSG_DEBUG, "end of time quest conditional");
pakout.AddDWord( Time ); // Time Left
//Log( MSG_DEBUG, "Time added");
for(dword j = 0; j < 10; j++) pakout.AddWord(thisclient->quest.quests[i].Variables[j]);
//Log( MSG_DEBUG, "added quest vars");
for(dword j = 0; j < 4; j++) pakout.AddByte(thisclient->quest.quests[i].Switches[j]);
//Log( MSG_DEBUG, "added quest switches");
for(dword j = 0; j < 5; j++)
{
if (thisclient->quest.quests[i].Items[j].itemnum != 0)
{
pakout.AddWord( thisclient->quest.quests[i].Items[j].GetPakHeader() );
pakout.AddDWord( thisclient->quest.quests[i].Items[j].GetPakData() );
}
else
{
pakout.AddWord( 0 );
pakout.AddDWord( 0 );
}
}
}
//Log( MSG_DEBUG, "finished main quest loop");
// testing out new PY quest flag method
for( unsigned i = 0; i < 0x40; i++ )
{
byte tempval = 0;
for(int j=0;j<8;j++)
{
tempval += (byte)thisclient->quest.Qflags[i][j] * (int)pow(2.0,(double)j);
}
pakout.AddByte(tempval);
//pakout.AddByte( thisclient->quest.flags[i] );
}
//Log( MSG_DEBUG, "finished quest flags");
// Wishlist? - Not Implemented
for (unsigned i = 0; i < 180; i++)
pakout.AddByte( 0 );
//Log( MSG_DEBUG, "Finished loading all the stuff into pakout");
thisclient->client->SendPacket( &pakout );
}
// Handle quest triggers
bool CWorldServer::pakQuestTrigger( CPlayer* thisclient, CPacket* pak )
{
byte action = pak->GetByte( 0 );
// action 1 = send text
// action 2 = delete quest
// action 3 = get quest
// action 4 = unknown
// action 5 = success
byte slot = pak->GetByte( 1 );
dword hash = pak->GetDWord( 2 );
if( thisclient->questdebug ) SendPM( thisclient, "Event Trigger recieved [%08x] Action %i", hash, action);
if (action == 2)
{
if( thisclient->questdebug ) SendPM( thisclient, "Delete quest - Slot %i", slot);
for (dword i = slot; i < 9; i++) thisclient->quest.quests[i] = thisclient->quest.quests[i+1];
thisclient->quest.quests[9].Clear();
CPacket pakout(0x730);
pakout.AddByte(0x03);
pakout.AddByte(slot);
pakout.AddDWord(hash);
thisclient->client->SendPacket(&pakout);
return true;
}
if (action != 3) return false;
int success = thisclient->ExecuteQuestTrigger(hash);
CPacket pakout(0x730);
pakout.AddByte(success);
pakout.AddByte(0);
pakout.AddDWord(hash);
thisclient->client->SendPacket(&pakout);
return true;
}
// Get this user set up with the encryption and stuff
bool CWorldServer::pakDoIdentify( CPlayer *thisclient, CPacket *P )
{
MYSQL_ROW row;
thisclient->Session->userid = GETDWORD((*P), 0);
memcpy( thisclient->Session->password, &P->Buffer[4], 32 );
MYSQL_RES *result = DB->QStore("SELECT username,lastchar,accesslevel,zulystorage,ktpoints,newpoints,logtime,totlogtime FROM accounts WHERE id=%i AND password='%s'", thisclient->Session->userid, thisclient->Session->password);
if(result==NULL) return false;
if (mysql_num_rows( result ) != 1)
{
Log( MSG_HACK, "Someone tried to connect to world server with an invalid account" );
DB->QFree( );
return false;
}
Log( MSG_DEBUG, "Loading Session Data" );
row = mysql_fetch_row(result);
strncpy_s( thisclient->Session->username, row[0],16 );
strncpy_s( thisclient->CharInfo->charname, row[1],16 );
thisclient->Session->accesslevel = atoi(row[2]);
thisclient->CharInfo->Storage_Zulies = atoi( row[3] );
thisclient->Session->KTPoints = atoi(row[4]); //load KTPoints
thisclient->Session->NewPoints = atoi(row[5]); //load newPoints. This is where additional KTPoints are added when they are purchased
thisclient->Session->logtime = atoi(row[6]); //current log time in hours.
thisclient->Session->TotalLogTime = atoi(row[7]); //total log time for this account
thisclient->Session->award = 0;
thisclient->Session->RespawnChoice = 0;
thisclient->Session->Respawned = 0;
thisclient->Session->inGame = true;
DB->QFree( );
if(thisclient->Session->NewPoints != 0)
{
// Add NewPoints to KTPoints
//Log( MSG_DEBUG, "Loaded up some new KTPoints and stuff" );
thisclient->Session->KTPoints += thisclient->Session->NewPoints;
// Set newpoints to zero both here and in the database
thisclient->Session->NewPoints = 0;
GServer->DB->QExecute("UPDATE accounts SET newpoints=%i, ktpoints=%i WHERE id=%i AND password='%s'",
thisclient->Session->NewPoints,thisclient->Session->KTPoints,thisclient->Session->userid, thisclient->Session->password);
//GServer->DB->QExecute("UPDATE accounts SET ktpoints=%i WHERE id=%i AND password='%s'",
// thisclient->Session->KTPoints,thisclient->Session->userid, thisclient->Session->password);
}
if (thisclient->Session->logtime >= Config.KTPointRate) //make the KTPoint reward system variable
{
while(thisclient->Session->logtime > Config.KTPointRate)
{
thisclient->Session->logtime -= Config.KTPointRate;
thisclient->Session->award ++;
}
thisclient->Session->KTPoints += thisclient->Session->award;
//thisclient->Union_s->unionvar[9] = thisclient->Session->KTPoints;
GServer->DB->QExecute("UPDATE accounts SET ktpoints=%i,logtime=%i WHERE id=%i AND password='%s'",
thisclient->Session->KTPoints, thisclient->Session->logtime, thisclient->Session->userid, thisclient->Session->password);
}
if(!thisclient->loaddata( )) return false;
Log( MSG_INFO, "User '%s'(#%i) logged in with character '%s'", thisclient->Session->username, thisclient->Session->userid, thisclient->CharInfo->charname);
BEGINPACKET( pak, 0x070c );
ADDBYTE ( pak, 0 );
ADDDWORD ( pak, 0x87654321 );
ADDDWORD ( pak, 0x00000000 );
thisclient->client->SendPacket( &pak );
pakPlayer(thisclient);
//Log( MSG_DEBUG, "ran pakPlayer");
pakInventory(thisclient);
//Log( MSG_DEBUG, "ran pakInventory");
pakQuestData(thisclient);
//Log( MSG_DEBUG, "ran pakQuestData");
RESETPACKET( pak, 0x7de );
ADDWORD ( pak, 0x1001 ); // 0x1001 to 0x1013 (game plan?)
ADDDWORD ( pak, 2 ); // options (plan time?) [2 = unlimited]
thisclient->client->SendPacket( &pak );
// Welcome message to the server
RESETPACKET( pak, 0x702 );
ADDSTRING ( pak, Config.WELCOME_MSG );
ADDBYTE ( pak, 0 );
thisclient->client->SendPacket( &pak );
SendSysMsg( thisclient, "Rush On Seven Slops - Pre-Evo Server based on KTROSE, proudly fcked up by Claude " );
thisclient->SetStats( );
if(thisclient->Session->award != 0)
{
char buffer[200];
sprintf ( buffer, "You have been awarded %i KTPoints for time logged into the server",thisclient->Session->award);
SendSysMsg(thisclient, buffer);
}
return true;
}
// Give the user an ID
bool CWorldServer::pakDoID( CPlayer* thisclient, CPacket* P )
{
// Assign a new id to this person
thisclient->clientid = GetNewClientID();
if (thisclient->clientid <= 0)
{
Log( MSG_WARNING, "User '%s'(#%i) denied access. Server is full.", thisclient->Session->username, thisclient->Session->userid );
return false;
}
Log( MSG_INFO, "User '%s'(#%i) assigned id #%i", thisclient->Session->username, thisclient->Session->userid, thisclient->clientid );
//Log( MSG_DEBUG, "User Session Ingame = %i", thisclient->Session->inGame);
//thisclient->Session->inGame = true;
if( thisclient->Party->party )
{
BEGINPACKET( pak, 0x7d5 );
ADDDWORD ( pak, thisclient->CharInfo->charid );
ADDWORD ( pak, thisclient->clientid );
ADDWORD ( pak, thisclient->GetMaxHP( ) );
ADDWORD ( pak, thisclient->Stats->HP );
ADDDWORD ( pak, 0x01000000 );
ADDDWORD ( pak, 0x0000000f );
ADDWORD ( pak, 0x1388 );
thisclient->Party->party->SendToMembers( &pak, thisclient );
}
BEGINPACKET( pak, 0x721 );
ADDWORD ( pak, 0x0022 );
ADDWORD ( pak, 0x0002 );
ADDWORD ( pak, 0x0000 );
thisclient->client->SendPacket( &pak );
//Log( MSG_DEBUG, "Packet 0x721 sent");
RESETPACKET( pak, 0x753 );
ADDWORD ( pak, thisclient->clientid ); // USER ID
//Log( MSG_DEBUG, "User ID added");
ADDWORD ( pak, thisclient->Stats->HP ); // CURRENT HP
//Log( MSG_DEBUG, "Current HP added");
ADDWORD ( pak, thisclient->Stats->MP ); // CURRENT MP
//Log( MSG_DEBUG, "Current MP added");
ADDDWORD ( pak, thisclient->CharInfo->Exp ); // CURRENT EXP
ADDDWORD ( pak, 0x00000000 ); // LVL EXP (UNSUSED)
//Log( MSG_DEBUG, "Current XP added");
//Log( MSG_DEBUG, "Basic info added");
// thanks to StrikeX to post this source
//[economy]
/*
ADDWORD ( pak, 0x0063 ); // World Rate
ADDBYTE ( pak, 0x70 );
ADDBYTE ( pak, 0x69 );
ADDBYTE ( pak, 0x68 );
ADDBYTE ( pak, 0x67 );
ADDWORD ( pak, 0x0062 ); // Town rate
ADDBYTE ( pak, 0x61 ); // misc rate
ADDBYTE ( pak, 0x32 ); //1
ADDBYTE ( pak, 0x32 ); //2
ADDBYTE ( pak, 0x32 ); //3
ADDBYTE ( pak, 0x32 ); //4
ADDBYTE ( pak, 0x32 ); //5
ADDBYTE ( pak, 0x32 ); //6
ADDBYTE ( pak, 0x32 ); //7
ADDBYTE ( pak, 0x32 ); //8
ADDBYTE ( pak, 0x32 ); //9
ADDBYTE ( pak, 0x32 ); //10
ADDBYTE ( pak, 0x32 ); //11
*/
ADDWORD ( pak, 0x0064 ); //world rate
ADDDWORD ( pak, 0x0C1F4B79);//0x1841f50b );
ADDWORD ( pak, 0x0064 ); //town rate
ADDDWORD ( pak, 0x3232cd50 );
ADDDWORD ( pak, 0x32323235 );
ADDDWORD ( pak, 0x35323232 );
//Log( MSG_DEBUG, "rates added");
CMap* map = MapList.Index[thisclient->Position->Map];
//Log( MSG_DEBUG, "position added");
if(map->allowpvp!=0)
ADDWORD(pak, 0x0001)//player vs player map
else
ADDWORD(pak, 0x0000)//non player vs player map
ADDWORD (pak, 0x0000 );//??
// Map Time
ADDDWORD( pak, map->MapTime );
//ADDBYTE ( pak, 0xde );// (new)
//ADDWORD ( pak, 0x0008 );//this change something in the mapicon (time) (new)
if(map->allowpvp==1)
{
ADDWORD(pak, 0x0000 );//red icon (map)
ADDWORD(pak, 0x0005 );//red icon (map)
} // pvp all vs all
else if(map->allowpvp==2) // pvp group vs group
{
/*ADDWORD(pak, thisclient->Clan->clanid );*/
ADDWORD(pak, 51);
}
else
{
ADDWORD(pak, 0x0002 );//white icon (map)
ADDWORD(pak, 0x0000 );//white icon (map)
}
thisclient->client->SendPacket( &pak );
//Log( MSG_DEBUG, "Sent 0x753 packet");
// Sort out weight stuff, make user not able to run if overweight
int weight = ( thisclient->GetCurrentWeight() / thisclient->GetMaxWeight() ) * 100;
if(weight>110)
thisclient->Status->CanAttack = false;
else
thisclient->Status->CanAttack = true;
if(weight>100)
thisclient->Status->CanRun = false;
else
thisclient->Status->CanRun = true;
thisclient->Stats->Move_Speed = thisclient->GetMoveSpeed( );
RESETPACKET( pak, 0x762 );
ADDWORD ( pak, thisclient->clientid );
ADDBYTE ( pak, weight );
thisclient->client->SendPacket( &pak );
// set speed
RESETPACKET(pak, 0x782 );
ADDWORD ( pak, thisclient->clientid );
ADDBYTE ( pak, thisclient->Status->Stance );
ADDWORD ( pak, thisclient->Stats->Mspd_base );
SendToVisible( &pak, thisclient );
thisclient->CleanPlayerVector( );
thisclient->Session->inGame = true;
thisclient->Session->Respawned = 0;
//Log( MSG_DEBUG, "Completed DoID");
return true;
}
// Move Characters in map
bool CWorldServer::pakMoveChar( CPlayer* thisclient, CPacket* P )
{
if( thisclient->Shop->open || (!thisclient->Ride->Drive && thisclient->Ride->Ride) || !thisclient->Status->CanMove )
return true;
thisclient->UpdatePosition( );
thisclient->Position->lastMoveTime = clock();
if( thisclient->Status->Stance == SITTING )
thisclient->Status->Stance = RUNNING;
ClearBattle( thisclient->Battle );
thisclient->Battle->target = GETWORD((*P), 0x00 );
thisclient->Position->destiny.x = GETFLOAT((*P), 0x02 )/100;
thisclient->Position->destiny.y = GETFLOAT((*P), 0x06 )/100;
if(thisclient->Ride->Drive) //update the destination for anyone riding in the back of my cart
{
CPlayer* otherclient = GServer->GetClientByCID( thisclient->Ride->charid );
if(otherclient != NULL)
{
otherclient->Stats->Move_Speed = thisclient->Stats->Move_Speed;
otherclient->Position->destiny.x = GETFLOAT((*P), 0x02 )/100;
otherclient->Position->destiny.y = GETFLOAT((*P), 0x06 )/100;
otherclient->UpdatePosition( );
//hmm not sending an update packet regarding otherclient are we? Do we need a packet here?
BEGINPACKET( pak1, 0x79a );
ADDWORD ( pak1, otherclient->clientid ); // USER ID
ADDWORD ( pak1, otherclient->Battle->target ); // TARGET
//LMA: it's in fact the distance from current to destiny and not the base speed...
ADDWORD ( pak1, (DWORD) (distance(otherclient->Position->current,otherclient->Position->destiny)*100));
//ADDWORD ( pak, thisclient->Stats->Move_Speed ); // MSPEED
ADDFLOAT ( pak1, GETFLOAT((*P), 0x02 ) ); // POSITION X
ADDFLOAT ( pak1, GETFLOAT((*P), 0x06 ) ); // POSITION Y
ADDWORD ( pak1, GETWORD((*P), 0x0a ) ); // POSITION Z (NOT USED)
SendToVisible( &pak1, otherclient );
}
}
BEGINPACKET( pak, 0x79a );
ADDWORD ( pak, thisclient->clientid ); // USER ID
ADDWORD ( pak, thisclient->Battle->target ); // TARGET
//LMA: it's in fact the distance from current to destiny and not the base speed...
ADDWORD ( pak, (DWORD) (distance(thisclient->Position->current,thisclient->Position->destiny)*100));
//ADDWORD ( pak, thisclient->Stats->Move_Speed ); // MSPEED
ADDFLOAT ( pak, GETFLOAT((*P), 0x02 ) ); // POSITION X
ADDFLOAT ( pak, GETFLOAT((*P), 0x06 ) ); // POSITION Y
ADDWORD ( pak, GETWORD((*P), 0x0a ) ); // POSITION Z (NOT USED)
SendToVisible( &pak, thisclient );
//Log(MSG_DEBUG,"Recieved move command and set destiny to X: %f Y: %f.",thisclient->Position->destiny.x,thisclient->Position->destiny.y);
return true;
}
// Stop Character movement
bool CWorldServer::pakStopChar( CPlayer* thisclient, CPacket* P )
{
ClearBattle( thisclient->Battle );
thisclient->Position->destiny.x = GETFLOAT((*P), 0x00 )/100;
thisclient->Position->destiny.y = GETFLOAT((*P), 0x04 )/100;
thisclient->Position->current=thisclient->Position->destiny;
BEGINPACKET( pak, 0x770 );
ADDWORD ( pak, thisclient->clientid ); // USER ID
ADDFLOAT ( pak, thisclient->Position->destiny.x*100 ); // POSITION X
ADDFLOAT ( pak, thisclient->Position->destiny.y*100 ); // POSITION Y
ADDWORD ( pak, GETWORD((*P), 0x08 ) ); // POSITION Z (NOT USED)
SendToVisible( &pak, thisclient );
return true;
}
// Spawn NPC
bool CWorldServer::pakSpawnNPC( CPlayer* thisclient, CNPC* thisnpc )
{
//Log(MSG_DEBUG,"spawning NPC type %i at X: %f Y: %f.",thisnpc->npctype,thisnpc->pos.x,thisnpc->pos.y);
BEGINPACKET( pak, 0x791 );
ADDWORD( pak, thisnpc->clientid );
ADDFLOAT( pak, thisnpc->pos.x*100 );
ADDFLOAT( pak, thisnpc->pos.y*100 );
ADDWORD( pak, 0xcdcd );
ADDWORD( pak, 0xcdcd );
ADDWORD( pak, 0xcdcd );
ADDWORD( pak, 0xcdcd );
ADDBYTE( pak, 0x00 );
ADDWORD( pak, 0x0000 );
ADDWORD( pak, 0x0000 );
ADDWORD( pak, 0x03e8 );
ADDWORD( pak, 0x0000 );
ADDWORD( pak, 0x0001 );
ADDWORD( pak, 0x0000 );//Buffs
ADDWORD( pak, 0x0000 );//Buffs
ADDWORD( pak, 0x0000 );//buffs
ADDWORD( pak, thisnpc->npctype );
if(thisnpc->thisnpc->dialogid != 0)
{
ADDWORD( pak, thisnpc->thisnpc->dialogid );
}
else
{// fixed by tomiz [npc dialogs fixed [still not all]]
unsigned int factor = 900;
//if (thisnpc->npctype >= 1000 && thisnpc->npctype <=1041 || thisnpc->npctype >= 1043 && thisnpc->npctype <=1084 || thisnpc->npctype >= 1086 && thisnpc->npctype <=1119 || thisnpc->npctype >= 1131 && thisnpc->npctype <=1199 || thisnpc->npctype >= 1207 && thisnpc->npctype <=1299) factor=900;
//else if (thisnpc->npctype >= 1200 && thisnpc->npctype <=1203) factor=896; // event npc
//else if (thisnpc->npctype == 1042 ) factor=899; // Storage Adventure Plain -> Fabrizio - Junon Clan Field -> Nell
//else if (thisnpc->npctype == 1081 ) factor=300;
//else if (thisnpc->npctype == 1085 ) factor=901;
//else if (thisnpc->npctype == 1205 ) factor=901; //santa
//else if (thisnpc->npctype == 1206 ) factor=1019; //Loelsch
//else if (thisnpc->npctype == 1120 ) factor=896; // dunno if that dialog are corect 1120 [Clan Clerk] Regina
//else if (thisnpc->npctype == 1204 ) factor=897; // event npc another warp to zant dialog npc 1203 [Event Info] Lucielle Fete
//else if (thisnpc->npctype == 1473 ) factor=1457; // should be ok 1473 Melendino adventure plain
//else if (thisnpc->npctype == 1752 ) factor=1528; // Clan Merchant Aliche Patt ver 141
//else if (thisnpc->npctype >= 1122 && thisnpc->npctype <=1130) factor=905;
//else if (thisnpc->npctype == 1502 ) factor=1198; //santa
//else if (thisnpc->npctype >= 1503 && thisnpc->npctype <=1599) factor=1210;
//else if (thisnpc->npctype >= 1750 && thisnpc->npctype <=1755 || !thisnpc->npctype == 1752 ) factor=1000; //should be ok
ADDWORD( pak, thisnpc->npctype - factor );
}
ADDFLOAT( pak, thisnpc->dir );
//if(thisnpc->npctype == 1115)
//{
// ADDBYTE( pak, GServer->Config.Cfmode ); // Burland Clan Field open/close
// ADDBYTE ( pak, 0 );
//}
//else
//{
if(thisnpc->thisnpc->eventid != 0)
{
ADDWORD (pak, thisnpc->thisnpc->eventid);
}
else
{
ADDWORD( pak, 0 );
}
//}
thisclient->client->SendPacket( &pak );
return true;
}
// Changes stance
bool CWorldServer::pakChangeStance( CPlayer* thisclient, CPacket* P )
{
/* #define ATTACKING 1
#define WALKING 2
#define RUNNING 3
#define DRIVING 4
#define SITTING
run-walk-run stancenum == 0
sit-stand-sit stancenum == 1
drive-no drive-drive == 2
*/
if(thisclient->Shop->open)
return true;
BYTE stancenum = GETBYTE((*P),0x00);
BYTE newstancenum = stancenum;
switch (stancenum)
{
case 0:
if(thisclient->Status->Stance == RUNNING) //change 3 to 2 running to walking
{
newstancenum = 2;
thisclient->Status->Stance = WALKING;
}
else if(thisclient->Status->Stance == WALKING) // Running
{
newstancenum = 3;
thisclient->Status->Stance = RUNNING;
}
break;
case 1:
if (thisclient->Status->Stance == RUNNING||thisclient->Status->Stance == WALKING)//>Status->Stance!=DRIVING && thisclient->Status->Stance>0x01)
{
newstancenum = 1;
thisclient->Status->Stance = SITTING;
}
else if (thisclient->Status->Stance == SITTING)//(thisclient->Status->Stance<0x04)
{
newstancenum = 3;
thisclient->Status->Stance = RUNNING;
}
break;
case 2:
if (thisclient->Status->Stance==RUNNING || thisclient->Status->Stance==WALKING) //getting in a cart
{// Clean Buff
newstancenum = 4;
thisclient->Status->Stance = DRIVING;
thisclient->Ride->Ride = false;
thisclient->Ride->Drive = true;
thisclient->Ride->charid = 0;
}
else if (thisclient->Status->Stance==DRIVING) //getting out of cart
{// Clean Buff
newstancenum = 3;
thisclient->Status->Stance = RUNNING;
thisclient->Ride->Ride = false;
thisclient->Ride->Drive = false;
thisclient->Ride->charid = 0;
}
break;
default:
newstancenum = 3;
thisclient->Status->Stance = RUNNING;
break;
}
// if(!thisclient->Status->CanMove)
// thisclient->Status->Stance = RUNNING;
if (!thisclient->Status->CanRun && newstancenum == 3) {
newstancenum = 2;
thisclient->Status->Stance = WALKING;
}
thisclient->Stats->Move_Speed = thisclient->GetMoveSpeed( );
BEGINPACKET( pak, 0x782 );
ADDWORD( pak, thisclient->clientid );
ADDBYTE( pak, newstancenum );
//ADDWORD( pak, thisclient->Stats->Move_Speed );
SendToVisible( &pak, thisclient );
//Log( MSG_INFO, "Stancenum %i newstancenum %i Stance %i", stancenum, newstancenum, thisclient->Status->Stance);
return true;
}
// Spawn Drop
bool CWorldServer::pakSpawnDrop( CPlayer* thisclient, CDrop* thisdrop )
{
BEGINPACKET( pak, 0x7a6 );
ADDFLOAT( pak, thisdrop->pos.x*100 );
ADDFLOAT( pak, thisdrop->pos.y*100 );
if (thisdrop->type==1)
{
// -- ZULY --
ADDWORD( pak, 0xccdf );//0xccccccdf );
ADDDWORD( pak, thisdrop->amount );
ADDWORD( pak, thisdrop->clientid );
ADDWORD( pak, 0x0000 );
ADDWORD( pak, 0x5f90 );
}
else
{
// -- ITEM --
ADDWORD( pak, BuildItemHead( thisdrop->item ) );
ADDDWORD( pak, thisdrop->amount );
ADDWORD( pak, thisdrop->clientid );
ADDDWORD( pak, BuildItemData( thisdrop->item ) );
}
thisclient->client->SendPacket( &pak );
return true;
}
// Player Left
void CWorldServer::pakClearUser( CPlayer* thisclient )
{
BEGINPACKET( pak, 0x794 );
ADDWORD( pak, thisclient->clientid );
SendToVisible( &pak, thisclient, false );
}
// Drop items on map
bool CWorldServer::pakDoDrop( CPlayer* thisclient, CPacket* P )
{
BYTE itemid = GETBYTE((*P), 0x0);
if(!CheckInventorySlot(thisclient, itemid ))
return false;
DWORD amount = GETDWORD((*P), 0x1);
if (itemid == 0)
{
if ( amount<1 ) return true;
if ( thisclient->CharInfo->Zulies < amount ) return true;
CDrop* thisdrop = new CDrop;
assert(thisdrop);
thisdrop->clientid = GetNewClientID();
thisdrop->type = 1; // ZULY
thisdrop->pos = RandInCircle( thisclient->Position->current, 3 );
thisdrop->posMap = thisclient->Position->Map;
thisdrop->droptime = time(NULL);
thisdrop->amount = amount;
thisdrop->owner = 0;
CMap* map = MapList.Index[thisdrop->posMap];
map->AddDrop( thisdrop );
thisclient->CharInfo->Zulies -= amount;
BEGINPACKET( pak, 0x71d );
ADDQWORD( pak, thisclient->CharInfo->Zulies );
thisclient->client->SendPacket( &pak );
}
else
{
CDrop* thisdrop = new CDrop;
assert(thisdrop);
thisdrop->clientid = GetNewClientID();
thisdrop->type = 2; // ITEM
thisdrop->pos = RandInCircle( thisclient->Position->current, 3 );
thisdrop->posMap = thisclient->Position->Map;
thisdrop->droptime = time(NULL);
thisdrop->amount = amount;
thisdrop->item = thisclient->items[itemid];
thisdrop->item.count = amount;
thisdrop->owner = 0;
CMap* map = MapList.Index[thisdrop->posMap];
map->AddDrop( thisdrop );
// fixed by tomiz [item count drop correctly and dissaper from inventory]
if(thisclient->items[itemid].itemtype >=10 && thisclient->items[itemid].itemtype <= 13)
{
if(thisclient->items[itemid].count<amount) return true;
thisclient->items[itemid].count -= amount;
if(thisclient->items[itemid].count <= 0) ClearItem(thisclient->items[itemid]);
}
else
{
ClearItem(thisclient->items[itemid]);
}
thisclient->UpdateInventory( itemid );
}
return true;
}
// Picks up item
bool CWorldServer::pakPickDrop( CPlayer* thisclient, CPacket* P )
{
try
{
if(thisclient->Shop->open)
return true;
thisclient->RestartPlayerVal( );
WORD dropid = GETWORD((*P), 0x00);
CDrop* thisdrop = GetDropByID( dropid, thisclient->Position->Map );
if (thisdrop == NULL)
{
SendSysMsg( thisclient, "That is not a valid drop" );
return true;
}
if (thisdrop->item.itemnum > 250 && thisdrop->item.itemnum < 272 && thisdrop->item.itemtype == 7)//&&thisdrop->item.itemtype<174)//251/261/271/socket jewel 171Ring 172Necklace 173Earrings
{
thisdrop->item.socketed = true;
thisdrop->item.durability = 100;
thisdrop->item.lifespan = 100;
thisdrop->item.refine = 0;
thisdrop->item.stats = 0;
}
//now find the item type for crafting
if(thisdrop->item.itemtype > 0 && thisdrop->item.itemtype < 10)
thisdrop->item.type = GServer->EquipList[thisdrop->item.itemtype].Index[thisdrop->item.itemnum]->type;
if(thisdrop->item.itemtype == 10)
thisdrop->item.type = GServer->UseList.Index[thisdrop->item.itemnum]->type;
if(thisdrop->item.itemtype == 11)
thisdrop->item.type = GServer->JemList.Index[thisdrop->item.itemnum]->type;
if(thisdrop->item.itemtype == 12)
thisdrop->item.type = GServer->NaturalList.Index[thisdrop->item.itemnum]->type;
if(thisdrop->item.itemtype == 14)
thisdrop->item.type = GServer->PatList.Index[thisdrop->item.itemnum]->type;
bool flag = false;
BEGINPACKET( pak, 0x7a7 );
ADDWORD ( pak, thisdrop->clientid );
CPlayer* dropowner = 0;
if( (thisdrop->owner == 0 || thisdrop->owner == thisclient->CharInfo->charid || time(NULL)-thisdrop->droptime >= 30 ) || ( thisclient->Party->party!=NULL && thisclient->Party->party == thisdrop->thisparty ))
{
if( thisclient->Party->party!=NULL )
{
unsigned int dropparty = thisclient->Party->party->Option/0x10;
if( dropparty == 8 ) // Orderly
{
unsigned int num = 0;
bool dpflag = false;
if( thisdrop->type == 1 )
{
num = thisclient->Party->party->LastZulies;
thisclient->Party->party->LastZulies++;
if( thisclient->Party->party->LastZulies>=thisclient->Party->party->Members.size() )
thisclient->Party->party->LastZulies = 0;
}
else
if( thisdrop->type == 2 )
{
num = thisclient->Party->party->LastItem;
thisclient->Party->party->LastItem++;
if( thisclient->Party->party->LastItem>=thisclient->Party->party->Members.size() )
thisclient->Party->party->LastItem = 0;
}
unsigned int n = 0;
while( !dpflag )
{
n++;
if( num>=thisclient->Party->party->Members.size() )
num = 0;
dropowner = thisclient->Party->party->Members.at( num );
if( dropowner == NULL )
num++;
else
{
dpflag = true;
num++;
}
if(n > 20) // not founded yet? >.>
{
dropowner = thisclient;
dpflag = true;
}
}
}
else // Equal Loot
{
dropowner = thisclient;
}
}
else
{
dropowner = thisclient;
}
if( thisdrop->type == 1 ) //Zulie
{
dropowner->CharInfo->Zulies += thisdrop->amount;
ADDWORD( pak, 0 );
ADDBYTE( pak, 0 );
ADDWORD( pak, 0xccdf );
ADDDWORD( pak, thisdrop->amount );
dropowner->client->SendPacket( &pak );
flag = true;
}
else
if( thisdrop->type == 2 ) // Item
{
if (thisdrop->item.type == 320) //instant effect item
{
RESETPACKET( pak,0x7a3 );
ADDWORD ( pak, dropowner->clientid );
ADDWORD ( pak, thisdrop->item.itemnum );
SendToVisible( &pak, dropowner );
flag = true;
switch (UseList.Index[thisdrop->item.itemnum]->useeffect[0])
{
case 16:
dropowner->Stats->HP += (UseList.Index[thisdrop->item.itemnum]->useeffect[1]);
if(dropowner->Stats->HP > dropowner->Stats->MaxHP )
dropowner->Stats->HP = dropowner->Stats->MaxHP;
break;
case 17:
dropowner->Stats->MP += (UseList.Index[thisdrop->item.itemnum]->useeffect[1]);
if(dropowner->Stats->MP > dropowner->Stats->MaxMP )
dropowner->Stats->MP = dropowner->Stats->MaxMP;
break;
case 76:
dropowner->CharInfo->stamina += (UseList.Index[thisdrop->item.itemnum]->useeffect[1]);
if(dropowner->CharInfo->stamina > 5000)
dropowner->CharInfo->stamina = 5000;
break;
case 92:
if(dropowner->Clan->clanid>0)
{
dropowner->Clan->CP += (UseList.Index[thisdrop->item.itemnum]->useeffect[1]);
DB->QExecute( "UPDATE list_clan set cp=%i where id=%i", dropowner->Clan->CP,dropowner->Clan->clanid);
RESETPACKET( pak, 0x7e0 );
ADDBYTE ( pak, 0x5C ); //action to update clan points (charserver)
ADDWORD ( pak, dropowner->Clan->clanid);
ADDWORD ( pak, dropowner->clientid );
ADDDWORD ( pak, dropowner->Clan->CP );
ADDWORD ( pak, 0x00);
SendISCPacket( &pak );
}
else
{
Log( MSG_WARNING, "Player collected clanpoints but is not in a clan");
}
break;
default:
Log( MSG_WARNING, "Unknown autoconsume type: %i %i",(UseList.Index[thisdrop->item.itemnum]->usecondition[0]),(UseList.Index[thisdrop->item.itemnum]->usecondition[1]));
break;
}
}
else
{
unsigned int tempslot = dropowner->AddItem( thisdrop->item );
if(tempslot != 0xffff)// we have slot
{
unsigned int slot1 = tempslot;
unsigned int slot2 = 0xffff;
if(tempslot > MAX_INVENTORY)
{
slot1 = tempslot / 1000;
slot2 = tempslot % 1000;
}
ADDBYTE ( pak, 0x00 );
ADDBYTE ( pak, slot1 );
ADDBYTE ( pak, 0x00 );
ADDWORD ( pak, BuildItemHead( dropowner->items[slot1] ) );
ADDDWORD ( pak, BuildItemData( dropowner->items[slot1] ) );
dropowner->client->SendPacket( &pak );
dropowner->UpdateInventory( slot1, slot2 );
flag = true;
}
else
{
ADDBYTE (pak, 0x03);
dropowner->client->SendPacket(&pak);
}
}
}
}
else
{
ADDBYTE (pak, 0x02);
thisclient->client->SendPacket(&pak);
}
if( flag )
{
if( thisclient->Party->party!=NULL )
{
unsigned int dropparty = thisclient->Party->party->Option/0x10;
if( dropparty == 8 )
{
RESETPACKET( pak, 0x7d3 );
ADDWORD ( pak, dropowner->clientid );
if( thisdrop->type == 1 )
{
ADDWORD ( pak, 0xccdf );
ADDDWORD( pak, thisdrop->amount );
}
else
if( thisdrop->type == 2 )
{
ADDWORD ( pak, BuildItemHead( thisdrop->item ) );
ADDDWORD ( pak, BuildItemData( thisdrop->item ) );
}
thisclient->Party->party->SendToMembers( &pak, dropowner );
}
}
CMap* map = MapList.Index[thisdrop->posMap];
pthread_mutex_lock( &map->DropMutex );
map->DeleteDrop( thisdrop );
pthread_mutex_unlock( &map->DropMutex );
}
return true;
}
catch(...)
{
Log( MSG_ERROR, "Error in pakpickdrop");
return false;
}
}
// Changes equipment
bool CWorldServer::pakChangeEquip( CPlayer* thisclient, CPacket* P )
{
if(thisclient->Shop->open)
return true;
WORD srcslot = GETWORD((*P), 0);
WORD destslot = GETWORD((*P), 2);
if(!CheckInventorySlot(thisclient, srcslot))
return false;
if(!CheckInventorySlot(thisclient, destslot))
return false;
if( destslot == 0 ) destslot = thisclient->GetNewItemSlot( thisclient->items[srcslot] );
if( destslot == 0xffff ) return true;
/*
if( srcslot==7 || destslot==7 )
{
// clear the buffs if we change the weapon
for(UINT i=0;i<15;i++)
{
switch(thisclient->MagicStatus[i].Buff)
{
case A_ATTACK:
case A_ACCUR:
case A_HASTE:
case A_CRITICAL:
thisclient->MagicStatus[i].Duration = 0;
break;
}
}
}
*/
if(destslot == 8) //trying to equip a shield
{
// first we will check if it is possible. Do we have a two handed weapon equipped?
UINT weapontype = EquipList[WEAPON].Index[thisclient->items[7].itemnum]->type;
switch(weapontype)
{
case TWO_HAND_SWORD:
case SPEAR:
case TWO_HAND_AXE:
case BOW:
case GUN:
case LAUNCHER:
case STAFF:
case KATAR:
case DOUBLE_SWORD:
case DUAL_GUN:
{
//yes we do. OK reject the shield then.
SendSysMsg( thisclient, "Cannot equip shield at this time" );
return true;
}
break;
default:
break;
}
}
CItem tmpitm;
tmpitm = thisclient->items[srcslot];
thisclient->items[srcslot] = thisclient->items[destslot];
thisclient->items[destslot] = tmpitm;
// thisclient->UpdateInventory( srcslot, destslot );
BEGINPACKET( pak,0x7a5 );
ADDWORD( pak, thisclient->clientid );
ADDWORD( pak, srcslot );
ADDDWORD( pak, BuildItemShow(thisclient->items[srcslot])); // ITEM
ADDWORD ( pak, thisclient->Stats->Move_Speed);
SendToVisible( &pak, thisclient );
if( srcslot == 7 || destslot == 7 )
{
// if is two hand weapon, we have to check if have shield and unequip it
UINT weapontype = EquipList[WEAPON].Index[thisclient->items[7].itemnum]->type;
switch(weapontype)
{
case TWO_HAND_SWORD:
case SPEAR:
case TWO_HAND_AXE:
case BOW:
case GUN:
case LAUNCHER:
case STAFF:
case KATAR:
case DOUBLE_SWORD:
case DUAL_GUN:
{
if(thisclient->items[8].itemnum != 0)
{ // we should unequip the shield
UINT newslot = thisclient->GetNewItemSlot( thisclient->items[8] );
if(newslot == 0xffff)
{
// we have no slot for the shield, we have to change back the items
tmpitm = thisclient->items[destslot];
thisclient->items[destslot] = thisclient->items[srcslot];
thisclient->items[srcslot] = tmpitm;
SendSysMsg( thisclient, "You don't have free slot" );
return true;
}
thisclient->items[newslot] = thisclient->items[8];
ClearItem( thisclient->items[8] );
thisclient->UpdateInventory( newslot, 8 );
RESETPACKET( pak, 0x7a5);
ADDWORD ( pak, thisclient->clientid );
ADDWORD ( pak, 8 );
ADDWORD ( pak, thisclient->items[8].itemnum );
ADDWORD ( pak, BuildItemRefine( thisclient->items[8] ) );
ADDWORD ( pak, thisclient->Stats->Move_Speed );
SendToVisible( &pak, thisclient );
/* STARTPACKET(pak2, 0x782, 11);
SETWORD( pak2, 0x00,thisclient->clientid );
SETBYTE( pak2, 0x02, thisclient->Status->Stance );
SETWORD( pak2, 0x03, thisclient->Stats->Move_Speed );
SendToVisible( &pak2, thisclient );*/
}
}
break;
default:
break;
}
}
STARTPACKET(pak3,0x718,21);
SETBYTE ( pak3, 0x00, 2); // ITEMS TO UPDATE
SETBYTE ( pak3, 0x01, srcslot);
SETWORD ( pak3, 0x02, BuildItemHead( thisclient->items[srcslot] ) );
SETDWORD ( pak3, 0x04, BuildItemData( thisclient->items[srcslot] ) );
SETBYTE ( pak3, 0x08, destslot);
SETWORD ( pak3, 0x09, BuildItemHead( thisclient->items[destslot] ) );
SETDWORD ( pak3, 0x0b, BuildItemData( thisclient->items[destslot] ) );
thisclient->client->SendPacket(&pak3);
//thisclient->UpdateInventory( srcslot, destslot );
thisclient->SetStats( );
return true;
}
// Construct a cart/change parts
bool CWorldServer::pakChangeCart( CPlayer* thisclient, CPacket* P )
{
if(thisclient->Shop->open)
return true;
WORD cartslot = GETWORD((*P), 0);
WORD srcslot = GETWORD((*P), 0) + 135;
WORD destslot = GETWORD((*P), 2);
if(!CheckInventorySlot( thisclient, srcslot ))
return false;
if(!CheckInventorySlot( thisclient, destslot ))
return false;
if( destslot == 0 ) destslot=thisclient->GetNewItemSlot( thisclient->items[srcslot] );
if( destslot == 0xffff ) return true;
CItem tmpitm = thisclient->items[srcslot];
thisclient->items[srcslot] = thisclient->items[destslot];
thisclient->items[destslot] = tmpitm;
BEGINPACKET( pak, 0x7ca );
ADDWORD ( pak, thisclient->clientid );
ADDWORD ( pak, cartslot);
ADDWORD ( pak, thisclient->items[srcslot].itemnum);
ADDWORD ( pak, BuildItemRefine( thisclient->items[srcslot] ) );
ADDWORD ( pak, thisclient->Stats->Move_Speed );
SendToVisible( &pak, thisclient );
thisclient->UpdateInventory( srcslot, destslot );
thisclient->Stats->Move_Speed = thisclient->GetMoveSpeed( );
return true;
}
// Start attacking a monster or player
bool CWorldServer::pakStartAttack( CPlayer* thisclient, CPacket* P )
{
WORD clientid = GETWORD((*P),0x00);
if ( thisclient->Battle->target == clientid ) return true; //no targetting yourself
int weapontype = EquipList[WEAPON].Index[thisclient->items[7].itemnum]->type;
if( weapontype == 231 && thisclient->items[132].count<1 ) //Bow and no arrows
return true;
else
if( weapontype == 232 && thisclient->items[133].count<1 ) //Gun and no bullets
return true;
else
if( weapontype == 233 && thisclient->items[134].count<1 ) //Launcher and no shells
return true;
else
if( weapontype == 271 && thisclient->items[132].count<1 ) //Crossbow and no arrows
return true;
CMap* map = MapList.Index[thisclient->Position->Map];
CCharacter* character = map->GetCharInMap( clientid );
if(character == NULL) return true;
if(character->IsMonster( ))
{
if(map->allowpvp == 0 && character->IsSummon( )) return true;
if(!character->IsSummon())
character->AddDamage((CCharacter*)thisclient, 0);
//}
//if(character->IsMonster())
//{
// SET MONSTER HEALTH
BEGINPACKET( pak, 0x79f );
ADDWORD ( pak, character->clientid );
ADDDWORD ( pak, character->Stats->HP );
thisclient->client->SendPacket( &pak );
}
thisclient->StartAction( character, NORMAL_ATTACK, 0 );
thisclient->Battle->contatk = true;
return true;
}
// Goto next map through gate
bool CWorldServer::pakGate( CPlayer* thisclient, CPacket* P )
{
thisclient->Session->inGame = false;
word GateID = GETWORD((*P), 0x00);
CTeleGate* thisgate = GetTeleGateByID( GateID );
fPoint position;
UINT map = 0;
// I'm setting this at 50 distance from the point of teleport. Increase if you run into
// broken telegates. We might need to dump the scale and work from that - Drakia
if( thisgate == NULL || thisclient->Position->Map != thisgate->srcMap || distance(thisclient->Position->current, thisgate->src) > 150 )
{
Log( MSG_HACK, "Player %s[Map: %i X: %f Y: %f] - Gate Hacking[ID: %i]",
thisclient->CharInfo->charname, thisclient->Position->Map,
thisclient->Position->current.x, thisclient->Position->current.y, GateID );
return true;
}
map = thisgate->destMap;
position = thisgate->dest;
MapList.Index[map]->TeleportPlayer( thisclient, position );
thisclient->saveinventory();
thisclient->quicksave();
thisclient->Session->inGame = true;
return true;
}
// Emotions
bool CWorldServer::pakDoEmote( CPlayer* thisclient, CPacket* P )
{
if(thisclient->Shop->open)
return true;
thisclient->RestartPlayerVal( );
BEGINPACKET( pak, 0x781 );
ADDWORD( pak, GETWORD((*P), 0) );
ADDWORD( pak, GETWORD((*P), 2) );
ADDWORD( pak, thisclient->clientid );
SendToVisible( &pak, thisclient );
return true;
}
// This function is for increasing your stats
bool CWorldServer::pakAddStats( CPlayer* thisclient, CPacket* P )
{
BYTE statid = GETBYTE((*P), 0);
int statval = -1;
int nstatval = 0;
switch(statid)
{
case 0: nstatval=(int)floor((float)thisclient->Attr->Str/5); break;
case 1: nstatval=(int)floor((float)thisclient->Attr->Dex/5); break;
case 2: nstatval=(int)floor((float)thisclient->Attr->Int/5); break;
case 3: nstatval=(int)floor((float)thisclient->Attr->Con/5); break;
case 4: nstatval=(int)floor((float)thisclient->Attr->Cha/5); break;
case 5: nstatval=(int)floor((float)thisclient->Attr->Sen/5); break;
default:
break;
}
if (thisclient->CharInfo->StatPoints>=nstatval && nstatval < ((Config.MaxStat/5)+1))
{
switch(statid)
{
case 0: statval=++thisclient->Attr->Str; break;
case 1: statval=++thisclient->Attr->Dex; break;
case 2: statval=++thisclient->Attr->Int; break;
case 3: statval=++thisclient->Attr->Con; break;
case 4: statval=++thisclient->Attr->Cha; break;
case 5: statval=++thisclient->Attr->Sen; break;
default:
break;
}
}
if (statval>0)
{
thisclient->CharInfo->StatPoints-=nstatval;
BEGINPACKET( pak, 0x7a9 );
ADDBYTE( pak, statid );
ADDWORD( pak, (unsigned short)statval );
thisclient->client->SendPacket( &pak );
}
thisclient->SetStats( );
return true;
}
// Normal Chat
bool CWorldServer::pakNormalChat( CPlayer* thisclient, CPacket* P )
{
if (P->Buffer[0]=='/')
{
return pakGMCommand( thisclient, P );
//std::cout << thisclient->CharInfo->charname << ": " << P->Buffer << "\n";
}
else
{
BEGINPACKET( pak, 0x783 );
ADDWORD( pak, thisclient->clientid );
ADDSTRING( pak, P->Buffer );
ADDBYTE( pak, 0 );
SendToVisible( &pak, thisclient );
}
return true;
};
// Exit rose
bool CWorldServer::pakExit( CPlayer* thisclient, CPacket* P )
{
BEGINPACKET( pak, 0x707 );
ADDWORD( pak, 0 );
thisclient->client->SendPacket( &pak );
thisclient->client->isActive = false;
return true;
}
// move skill to function keys
bool CWorldServer::pakMoveSkill ( CPlayer* thisclient, CPacket* P )
{
BYTE slotid = GETBYTE((*P), 0x0 );
WORD itemid = GETWORD((*P), 0x1 );
if(slotid>47) return true;
thisclient->quickbar[slotid] = itemid;
BEGINPACKET( pak, 0x7aa );
ADDBYTE( pak, slotid );
ADDWORD( pak, itemid );
thisclient->client->SendPacket( &pak );
return true;
}
// User is checking up on the server
bool CWorldServer::pakPing ( CPlayer* thisclient, CPacket* P )
{
BEGINPACKET( pak, 0x0700 );
ADDWORD( pak, 0 );
thisclient->client->SendPacket( &pak );
return true;
}
// GameGuard
bool CWorldServer::pakGameGuard ( CPlayer* thisclient, CPacket* P )
{
thisclient->lastGG = clock();
return true;
}
// User Died
bool CWorldServer::pakUserDied ( CPlayer* thisclient, CPacket* P )
{
thisclient->Session->inGame = false;
thisclient->Session->Respawned = 1;
//BYTE respawn = GETBYTE((*P),0);
thisclient->Session->RespawnChoice = GETBYTE((*P),0);
//PY lets try moving all this stuff into the main loop because we are currently outside of the player mutex
//It's all in pakRespawned now.
//thisclient->Session->inGame is just used as a toggle trigger now
/*
Log( MSG_INFO, "RespawnZones choise: %i", respawn );
//1 - Current / 2 - save point/dungeon entrance
CMap* map = MapList.Index[thisclient->Position->Map];
CRespawnPoint* thisrespawn = NULL;
thisclient->Stats->HP = thisclient->Stats->MaxHP * 10 / 100;
if(respawn == 1 || map->dungeon)
{
if (respawn != 1) // This is a dungeon map, spawn at start
thisrespawn = map->GetStartRespawn( );
else
thisrespawn = map->GetNearRespawn( thisclient );
if(thisrespawn!=NULL)
{
map->TeleportPlayer( thisclient, thisrespawn->dest, false );
}
}
else // This is a field, spawn in save town
{
thisrespawn = GetRespawnByMap( thisclient->Position->saved );
if(thisrespawn != NULL)
{
fPoint coord = thisrespawn->dest;
MapList.Index[thisclient->Position->saved]->TeleportPlayer( thisclient, coord, false );
}
}
if(thisrespawn == NULL)
{
fPoint coord;
coord.x = 5200;
coord.y = 5200;
MapList.Index[2]->TeleportPlayer( thisclient, coord, false );
}
for(unsigned int i=0;i<30;i++)
{ // Clean Buffs
thisclient->MagicStatus[i].Duration = 0;
}*/
return true;
}
// User Save Town
bool CWorldServer::pakSaveTown ( CPlayer* thisclient, CPacket* P )
{
thisclient->Position->saved = thisclient->Position->Map;
GServer->DB->QExecute("UPDATE characters SET townid=%i WHERE id=%i",thisclient->Position->saved,thisclient->CharInfo->charid );
return true;
}
// Shouting
bool CWorldServer::pakShout ( CPlayer* thisclient, CPacket* P )
{
BEGINPACKET(pak, 0x0785);
ADDSTRING ( pak, thisclient->CharInfo->charname );
ADDBYTE ( pak, 0 );
ADDSTRING ( pak, &P->Buffer[0] );
ADDBYTE ( pak, 0 );
SendToMap ( &pak, thisclient->Position->Map );
return true;
}
// Whispering
bool CWorldServer::pakWhisper ( CPlayer* thisclient, CPacket* P )
{
char msgto[17];
memset( &msgto, '\0', 17 );
strncpy_s( msgto, (char*)&(*P).Buffer[0],16 );
CPlayer* otherclient = GetClientByCharName( msgto );
if(otherclient!=NULL)
{
BEGINPACKET( pak, 0x0784 );
ADDSTRING( pak, thisclient->CharInfo->charname );
ADDBYTE( pak, 0 );
ADDSTRING( pak, &P->Buffer[strlen(msgto)+1] );
ADDBYTE( pak, 0 );
otherclient->client->SendPacket( &pak );
return true;
}
BEGINPACKET( pak, 0x0784 );
ADDSTRING( pak, msgto );
ADDBYTE( pak, 0 );
ADDBYTE( pak, 0 );
thisclient->client->SendPacket( &pak );
return true;
}
// Return to Char Select
bool CWorldServer::pakCharSelect ( CPlayer* thisclient, CPacket* P )
{
if(!thisclient->Session->inGame) return true;
BEGINPACKET( pak, 0x707 );
ADDWORD( pak, 0 );
thisclient->client->SendPacket( &pak );
thisclient->Session->inGame=false;
RESETPACKET( pak, 0x7e1 );
ADDBYTE ( pak, 0xfa );
ADDWORD ( pak, thisclient->Session->userid );//CharInfo->charid );
ADDBYTE ( pak, 0x00 );
SendISCPacket( &pak );
for(unsigned j=0; j<thisclient->VisiblePlayers.size(); j++) {
CPlayer* otherclient=thisclient->VisiblePlayers.at(j);
thisclient->ClearObject(otherclient->clientid);
}
for(unsigned j=0; j<thisclient->VisibleMonsters.size(); j++) {
thisclient->ClearObject(thisclient->VisibleMonsters.at(j));
}
for(unsigned j=0; j<thisclient->VisibleDrops.size(); j++) {
CDrop* thisdrop = thisclient->VisibleDrops.at(j);
thisclient->ClearObject(thisdrop->clientid);
}
for(unsigned j=0; j<thisclient->VisibleNPCs.size(); j++) {
CNPC* thisnpc = thisclient->VisibleNPCs.at(j);
thisclient->ClearObject( thisnpc->clientid );
}
thisclient->savedata();
RESETPACKET( pak, 0x505 );
ADDWORD ( pak, thisclient->Session->userid );
SendISCPacket( &pak );
thisclient->Session->isLoggedIn = false;
thisclient->Saved = true;
pakClearUser( thisclient );
ClearClientID( thisclient->clientid );
if(thisclient->client!=NULL) thisclient->client->isActive = false;
return true;
}
// Buy from NPC
bool CWorldServer::pakNPCBuy ( CPlayer* thisclient, CPacket* P )
{
//try
//{
if(thisclient->Shop->open)
return true;
WORD NPC = GETWORD((*P), 0);
CNPC* thisnpc = GetNPCByID( NPC, thisclient->Position->Map );
if( thisnpc == NULL )
return true;
BYTE buycount = GETBYTE((*P), 2);
BYTE sellcount = GETBYTE((*P), 3);
//Union Shop case...
Log(MSG_INFO,"Buying /selling from NPC %i. Buycount: %i, Sellcount: %i" ,thisnpc->npctype, buycount,sellcount);
bool is_unionshop = false;
//if (thisnpc->npctype == 1109 || thisnpc->npctype == 1110 || thisnpc->npctype == 1111 || thisnpc->npctype == 1112 || thisnpc->npctype == 1043)
//{
// is_unionshop = true;
// Log(MSG_INFO,"identified as a union shop");
//}
switch(thisnpc->npctype)
{
case 1109:
case 1110:
case 1111:
case 1112:
case 1043:
is_unionshop = true;
Log(MSG_INFO,"identified as a union shop");
break;
}
int UpointCost = 0;
int UnionVar = thisclient->Union_s->unionvar[0];
int TotUpointCost = 0;
BYTE ncount = 0;
BEGINPACKET( pak, 0x717 );
ADDQWORD ( pak, thisclient->CharInfo->Zulies );
ADDBYTE ( pak, 0x00 );
for (int i=0; i<buycount; i++)
{
BYTE tabid = GETBYTE((*P), 8+(i*4));
BYTE itemid = GETBYTE((*P), 9+(i*4)); //position in shop tab
WORD count = GETWORD((*P), 10+(i*4));
//Log( MSG_WARNING, "Buying item %i. ID %i, count %i", i, itemid, count);
unsigned sellid = 0;
switch(tabid)
{
case 0:
sellid = thisnpc->thisnpc->tab1;
break;
case 1:
sellid = thisnpc->thisnpc->tab2;
break;
case 2:
sellid = thisnpc->thisnpc->tab3;
break;
case 3:
sellid = thisnpc->thisnpc->specialtab;
break;
default:
sellid = 0;
}
if(SellList.Index[sellid]==NULL)
{ // invalid tab
//Log( MSG_WARNING, "Bad tab ID");
continue;
}
int tmpcount = count;
while (tmpcount > 0)
{
CItem thisitem;
thisitem.itemnum = SellList.Index[sellid]->item[itemid] % 1000;
thisitem.itemtype = SellList.Index[sellid]->item[itemid] / 1000;
thisitem.count = count;
//Log( MSG_WARNING, "Item purchased. type = %i. id = %i. tempcount = %i", thisitem.itemtype,thisitem.itemnum,tmpcount);
if(thisitem.itemtype <= 9)
{
UpointCost = GServer->EquipList[thisitem.itemtype].Index[thisitem.itemnum]->unionpoint;
thisitem.type = GServer->EquipList[thisitem.itemtype].Index[thisitem.itemnum]->type;
thisitem.durability = EquipList[thisitem.itemtype].Index[thisitem.itemnum]->durability;
}
if(thisitem.itemtype == 10)
{
UpointCost = GServer->UseList.Index[thisitem.itemnum]->unionpoint;
thisitem.type = GServer->UseList.Index[thisitem.itemnum]->type;
thisitem.durability = 0;
}
if(thisitem.itemtype == 11)
{
UpointCost = GServer->JemList.Index[thisitem.itemnum]->unionpoint;
thisitem.type = GServer->JemList.Index[thisitem.itemnum]->type;
thisitem.durability = 0;
}
if(thisitem.itemtype == 12)
{
UpointCost = GServer->NaturalList.Index[thisitem.itemnum]->unionpoint;
thisitem.type = GServer->NaturalList.Index[thisitem.itemnum]->type;
thisitem.durability = 0;
}
if(thisitem.itemtype == 14)
{
UpointCost = GServer->PatList.Index[thisitem.itemnum]->unionpoint;
thisitem.type = GServer->PatList.Index[thisitem.itemnum]->type;
thisitem.durability = GServer->PatList.Index[thisitem.itemnum]->durability;
}
if(is_unionshop && UpointCost == 0)
{
ncount++;
Log( MSG_WARNING, "Item has no price in Server");
tmpcount = 0;
continue; //this item has no price so skip it
}
if(is_unionshop && thisclient->Union_s->unionvar[UnionVar] < UpointCost)
{
ncount++;
Log( MSG_WARNING, "You cannot afford this item");
tmpcount = 0;
continue; //can't afford the item so don't bother adding it
}
//Log( MSG_WARNING, "Item purchased. type = %i. id = %i", thisitem.itemtype,thisitem.itemnum);
unsigned newslot = thisclient->GetNewItemSlot( thisitem );
if ( newslot == 0xffff )
{
ncount -= 1;
Log( MSG_WARNING, "failed to find free slot");
break;
}
int thisslotcount = 999 - thisclient->items[newslot].count;
//Log( MSG_WARNING, "this slot count = %i", thisslotcount);
//if ( thisslotcount > tmpcount )
//{
// thisslotcount = tmpcount;
//}
//Log( MSG_WARNING, "this slot count = %i", thisslotcount);
tmpcount -= thisslotcount;
thisitem.count += thisclient->items[newslot].count;
thisitem.refine = 0;
thisitem.lifespan = 100;
thisitem.appraised = true;
thisitem.socketed = false;
thisitem.stats = 0;
if(is_unionshop) //make sure all union shop items come with extra stats
{
if(thisitem.itemtype <= 9)
thisitem.stats = GServer->RandNumber(1,299);
}
thisitem.gem = 0;
thisclient->items[newslot] = thisitem;
ADDBYTE ( pak, newslot );
ADDWORD ( pak, BuildItemHead( thisclient->items[newslot] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[newslot] ) );
switch(thisitem.itemtype)
{
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 8:
case 9:
case 14:
{
float price = 0;
UINT quality = 0;
UINT bprice = 0;
if(thisitem.itemtype<10 )
{
quality = EquipList[thisitem.itemtype].Index[thisitem.itemnum]->quality;
bprice = EquipList[thisitem.itemtype].Index[thisitem.itemnum]->price;
}
else
{
quality = PatList.Index[thisitem.itemnum]->quality;
bprice = PatList.Index[thisitem.itemnum]->price;
}
price = quality;
price += 0x32; // town rate
price *= bprice;
price += 0.5;
price /= 100;
price = (float)round(price);
//Log( MSG_WARNING, "Item bought: itemnum %i, itemtype %i, itemcount %i, price %0.0f", thisitem.itemnum, thisitem.itemtype, thisitem.count, price);
if(is_unionshop)
{
thisclient->Union_s->unionvar[UnionVar] -= UpointCost;
if(UnionVar == 9)
{
Log( MSG_WARNING, "Union Shop Item bought: UnionID %i, itemnum %i, itemtype %i, itemcount %i, price %i", UnionVar, thisitem.itemnum, thisitem.itemtype, thisitem.count, UpointCost);
GServer->DB->QExecute("UPDATE accounts SET ktpoints=%i WHERE id=%i AND password='%s'",
thisclient->Union_s->unionvar[UnionVar],thisclient->Session->userid, thisclient->Session->password);
Log(MSG_DEBUG,"KTPoints updated and saved to the database");
Log( MSG_WARNING, "item Purchased successfully");
}
}
else
thisclient->CharInfo->Zulies -= (long int)price;
}
break;
case 10:
case 12:
{
// this values should be the same as packet 753
//Log( MSG_WARNING, "Type %i item selected", thisitem.itemtype);
BYTE values[11] = {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32};
UINT type = 0;
UINT bprice = 0;
UINT pricerate = 0;
UINT pvalue = 0;
if(thisitem.itemtype == 10)
{
type = UseList.Index[thisitem.itemnum]->type;
bprice = UseList.Index[thisitem.itemnum]->price;
pricerate = UseList.Index[thisitem.itemnum]->pricerate;
pvalue = UseList.Index[thisitem.itemnum]->pricevalue;
}
else
{
type = NaturalList.Index[thisitem.itemnum]->type;
bprice = NaturalList.Index[thisitem.itemnum]->price;
pricerate = NaturalList.Index[thisitem.itemnum]->pricerate;
pvalue = NaturalList.Index[thisitem.itemnum]->pricevalue;
}
unsigned int value = 0;
float price = 0;
bool flag;
if(type<421)
if(type<311)
flag = false;
else
if(type>312)
flag = false;
else
flag = true;
else
if(type<=428)
flag = true;
else
if(type<311)
flag = false;
else
flag = true;
if(flag)
{
value = pvalue;
if(value>=11)
value ^= 0xffffffff;
else
value = values[value];
value -= 0x32;
value *= pricerate;
price = value * 0.001;
price += 1;
price *= bprice;
price += 0.5;
price = (float)floor(price);
//Log( MSG_WARNING, "Item bought: itemnum %i, itemtype %i, itemcount %i, price %0.0f, flag %i", thisitem.itemnum, thisitem.itemtype, thisitem.count, price, flag);
if(is_unionshop)
{
thisclient->Union_s->unionvar[UnionVar] -= (UpointCost * count);
TotUpointCost -= (UpointCost * count);
if(UnionVar == 9)
{
Log( MSG_WARNING, "Union Shop Item bought: UnionID %i, itemnum %i, itemtype %i, itemcount %i, price %i", UnionVar, thisitem.itemnum, thisitem.itemtype, thisitem.count, UpointCost);
GServer->DB->QExecute("UPDATE accounts SET ktpoints=%i WHERE id=%i AND password='%s'",
thisclient->Union_s->unionvar[UnionVar],thisclient->Session->userid, thisclient->Session->password);
Log(MSG_DEBUG,"KTPoints updated and saved to the database");
Log( MSG_WARNING, "item Purchased successfully");
}
//Log( MSG_WARNING, "item Purchased successfully");
}
else
thisclient->CharInfo->Zulies -= (long int)price * count;
}
else
{
price = pricerate;
value = 0x61 - 0x32; // misc rate - 0x32
price *= value;
price *= 0.001;
price += 1;
price *= bprice;
price += 0.5;
price = (float)floor(price);
//Log( MSG_WARNING, "Item bought: itemnum %i, itemtype %i, itemcount %i, price %0.0f, flag %i", thisitem.itemnum, thisitem.itemtype, thisitem.count, price, flag);
if(is_unionshop)
{
thisclient->Union_s->unionvar[UnionVar] -= (UpointCost * count);
//Log( MSG_WARNING, "Union Shop Item bought: UnionID %i, itemnum %i, itemtype %i, itemcount %i, price %i", UnionVar, thisitem.itemnum, thisitem.itemtype, thisitem.count, UpointCost);
TotUpointCost -= (UpointCost * count);
if(UnionVar == 9)
{
Log( MSG_WARNING, "Union Shop Item bought: UnionID %i, itemnum %i, itemtype %i, itemcount %i, price %i", UnionVar, thisitem.itemnum, thisitem.itemtype, thisitem.count, UpointCost);
GServer->DB->QExecute("UPDATE accounts SET ktpoints=%i WHERE id=%i AND password='%s'",
thisclient->Union_s->unionvar[UnionVar],thisclient->Session->userid, thisclient->Session->password);
Log(MSG_DEBUG,"KTPoints updated and saved to the database");
Log( MSG_WARNING, "item Purchased successfully");
}
//Log( MSG_WARNING, "item Purchased successfully");
}
else
thisclient->CharInfo->Zulies -= (long int)price * count;
}
}
break;
case 7:
case 11:
case 13:
{
float price = 0;
UINT bprice = 0;
UINT pricerate;
if(thisitem.itemtype==7)
{
pricerate = EquipList[7].Index[thisitem.itemnum]->pricerate;
bprice = EquipList[7].Index[thisitem.itemnum]->price;
}
else
{
switch(thisitem.itemtype)
{
case 11:
pricerate = JemList.Index[thisitem.itemnum]->pricerate;
bprice = JemList.Index[thisitem.itemnum]->price;
break;
case 13:continue;
}
}
price = pricerate;
unsigned int value = 0x61 - 0x32; // misc rate - 0x32
price *= value;
price *= 0.001;
price += 1;
price *= bprice;
price += 0.5;
price = (float)round(price);
if(thisitem.itemtype == 7)
price = (float)round(bprice * 1.3);
//Log( MSG_WARNING, "Item bought: itemnum %i, itemtype %i, itemcount %i, price %0.0f", thisitem.itemnum, thisitem.itemtype, thisitem.count, price);
if(is_unionshop)
{
thisclient->Union_s->unionvar[UnionVar] -= UpointCost;
//Log( MSG_WARNING, "Union Shop Item bought: UnionID %i, itemnum %i, itemtype %i, itemcount %i, price %i", UnionVar, thisitem.itemnum, thisitem.itemtype, thisitem.count, UpointCost);
TotUpointCost -= UpointCost;
if(UnionVar == 9)
{
Log( MSG_WARNING, "Union Shop Item bought: UnionID %i, itemnum %i, itemtype %i, itemcount %i, price %i", UnionVar, thisitem.itemnum, thisitem.itemtype, thisitem.count, UpointCost);
GServer->DB->QExecute("UPDATE accounts SET ktpoints=%i WHERE id=%i AND password='%s'",
thisclient->Union_s->unionvar[UnionVar],thisclient->Session->userid, thisclient->Session->password);
Log(MSG_DEBUG,"KTPoints updated and saved to the database");
Log( MSG_WARNING, "item Purchased successfully");
}
//Log( MSG_WARNING, "item Purchased successfully");
}
else
thisclient->CharInfo->Zulies -= (long int)price*count;
}
break;
default:
Log( MSG_WARNING, "Invalid Item Type: %i", thisitem.itemtype );
break;
}
ncount++;
Log( MSG_WARNING, "item count: %i", ncount );
}
BEGINPACKET(pak1, 0x720 );
ADDWORD(pak1, thisclient->Union_s->unionvar[0] );
ADDDWORD(pak1, TotUpointCost);
thisclient->client->SendPacket( &pak1 );
}
for (int i=0; i<sellcount; i++)
{
BYTE slotid = GETBYTE((*P), 8+(buycount*4)+(i*3));
WORD count = GETWORD((*P), 9+(buycount*4)+(i*3));
CItem thisitem = thisclient->items[slotid];
thisitem.count = count;
switch(thisitem.itemtype)
{
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 8:
case 9:
case 14:
{
float price = 0;
price = 7.142857E-05F * 5000;
if(thisitem.itemtype<10)
{
price *= EquipList[thisitem.itemtype].Index[thisitem.itemnum]->price;
}
else
{
price *= PatList.Index[thisitem.itemnum]->price;
}
price *= thisitem.durability + 0xc8;
price *= 40;
price *= 0xc8 - 0x62; //town rate
price *= 1.000000E-06;
price = (float)floor(price);
//Log( MSG_WARNING, "Item Sold: itemnum %i, itemtype %i, itemcount %i, price %0.0f", thisitem.itemnum, thisitem.itemtype, thisitem.count, price);
thisclient->CharInfo->Zulies += (long int)price*count;
}
break;
case 10:
case 12:
{
// this values are the same from packet 753
BYTE values[11] = {0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32};
UINT type = 0;
UINT bprice = 0;
UINT pricerate = 0;
UINT pvalue = 0;
if(thisitem.itemtype==10)
{
type = UseList.Index[thisitem.itemnum]->type;
bprice = UseList.Index[thisitem.itemnum]->price;
pricerate = UseList.Index[thisitem.itemnum]->pricerate;
pvalue = UseList.Index[thisitem.itemnum]->pricevalue;
}
else
{
type = NaturalList.Index[thisitem.itemnum]->type;
bprice = NaturalList.Index[thisitem.itemnum]->price;
pricerate = NaturalList.Index[thisitem.itemnum]->pricerate;
pvalue = NaturalList.Index[thisitem.itemnum]->pricevalue;
}
unsigned int value = 0;
float price = 0;
bool flag;
if(type<421)
{
if(type<311)
flag = false;
else
if(type>312)
flag = false;
else
flag = true;
}
else
{
if(type<=428)
flag = true;
else
if(type<311)
flag = false;
else
flag = true;
}
if(flag)
{
value = pvalue;
if(value>=11)
value ^= 0xffffffff;
else
value = values[value];
value -= 0x32;
value *= pricerate;
value += 1000;
value *= bprice;
value *= (200 - 0x62); //town rate ( 100)
price = value * 5.555555555555556E-06;
price = (float)floor(price);
//Log( MSG_WARNING, "Item Sold: itemnum %i, itemtype %i, itemcount %i, price %0.0f", thisitem.itemnum, thisitem.itemtype, thisitem.count, price);
thisclient->CharInfo->Zulies += (long int)price*count;
}
else
{
price = pricerate;
value = 0x61 - 0x32; // misc rate -0x32
price *= value;
price += 1000;
price *= bprice;
price *= (200 - 0x62); //town rate ( 100)
price *= 5.555555555555556E-06;
price = (float)floor(price);
//Log( MSG_WARNING, "Item Sold: itemnum %i, itemtype %i, itemcount %i, price %0.0f", thisitem.itemnum, thisitem.itemtype, thisitem.count, price);
thisclient->CharInfo->Zulies += (long int)price*count;
}
}
break;
case 7:
case 11:
case 13:
{
float price = 0;
UINT bprice = 0;
UINT pricerate = 0;
switch(thisitem.itemtype)
{
case 7:
pricerate = EquipList[thisitem.itemtype].Index[thisitem.itemnum]->pricerate;
bprice = EquipList[thisitem.itemtype].Index[thisitem.itemnum]->price;
break;
case 11:
pricerate = JemList.Index[thisitem.itemnum]->pricerate;
bprice = JemList.Index[thisitem.itemnum]->price;
break;
case 13:continue;//can we sell quest items? :S
}
price = pricerate;
price *= 0x61 - 0x32; // misc rate -0x32
price += 1000;
price *= bprice;
price *= (200 - 0x62); //town rate ( 100)
price *= 5.555555555555556E-06;
price = (float)floor(price);
if(thisitem.itemtype == 7)
price = (float)floor(bprice * 0.5555508);
//Log( MSG_WARNING, "Item Sold: itemnum %i, itemtype %i, itemcount %i, price %0.0f", thisitem.itemnum, thisitem.itemtype, thisitem.count, price);
thisclient->CharInfo->Zulies += (long int)price*count;
}
break;
default:
Log( MSG_WARNING, "Invalid Item Type: %i", thisitem.itemtype );
break;
}
thisclient->items[slotid].count -= count;
if( thisclient->items[slotid].count <=0 )
ClearItem( thisclient->items[slotid] );
ADDBYTE( pak, slotid );
ADDWORD( pak, BuildItemHead( thisclient->items[slotid] ) );
ADDDWORD( pak, BuildItemData( thisclient->items[slotid] ) );
ncount++;
}
SETQWORD( pak, 0, thisclient->CharInfo->Zulies );
SETBYTE( pak, 8, ncount );
thisclient->client->SendPacket( &pak );
thisclient->saveinventory();
return true;
//}
//__seh_except(info, context)
//{
// Log( MSG_ERROR, "Error in pakNPCBuy");
// return false;
//}
//__seh_end
}
// Trade action
bool CWorldServer::pakTradeAction ( CPlayer* thisclient, CPacket* P )
{
if(thisclient->Shop->open)
return true;
CPacket pak;
BYTE action = GETBYTE( (*P), 0 );
thisclient->Trade->trade_target = GETWORD( (*P), 1 );
CPlayer* otherclient = GetClientByID( thisclient->Trade->trade_target, thisclient->Position->Map );
if (otherclient == NULL) return true;
switch(action)
{
case 0:
// REQUEST TRADE
RESETPACKET( pak, 0x7c0 );
ADDBYTE( pak, 0 );
ADDWORD( pak, thisclient->clientid );
ADDBYTE( pak, 0 );
otherclient->client->SendPacket( &pak ); // send the request packet to the other player with action zero
thisclient->Trade->trade_status = 2; // requesting trade.
otherclient->Trade->trade_status = 1; // other client needs to respond
break;
case 1:
// ACCEPT TRADE
RESETPACKET( pak, 0x7c0 );
ADDBYTE( pak, 1 );
ADDWORD( pak, thisclient->clientid );
ADDBYTE( pak, 0 );
otherclient->client->SendPacket( &pak ); // send a trade accept packet
thisclient->Trade->trade_status = 3; // set both trade status bits to 3 (trade window open for both players)
otherclient->Trade->trade_status = 3;
for(int i=0; i<11; i++) thisclient->Trade->trade_count[i] = 0;
for(int i=0; i<10; i++) thisclient->Trade->trade_itemid[i] = 0;
for(int i=0; i<11; i++) otherclient->Trade->trade_count[i] = 0;
for(int i=0; i<10; i++) otherclient->Trade->trade_itemid[i] = 0;
break;
case 2: // REJECT TRADE
case 3: // CANCEL TRADE
// reject and cancel both do the same thing
RESETPACKET( pak, 0x7c0 );
ADDBYTE( pak, 3 );
ADDWORD( pak, thisclient->clientid );
ADDBYTE( pak, 0 );
otherclient->client->SendPacket( &pak ); // send packet to cancel trade
thisclient->Trade->trade_target = 0; // remove trade targets from both clients.
otherclient->Trade->trade_target = 0;
thisclient->Trade->trade_status = 0; // set trade status to 0 for both clients
thisclient->Trade->trade_status = 0;
break;
case 4:
// CHECK READY
RESETPACKET( pak, 0x7c0 );
ADDBYTE( pak, 4 );
ADDWORD( pak, thisclient->clientid );
ADDBYTE( pak, 0 );
otherclient->client->SendPacket( &pak ); // send trade locked packet to other client
thisclient->Trade->trade_status = 4; // set MY OWN trade status to locked
break;
case 5:
// UNCHECK READY
// seems we can't do this right now
break;
case 6:
// TRADE DONE
if (thisclient->Trade->trade_status == 6)
thisclient->Trade->trade_status = 4;
else
thisclient->Trade->trade_status = 6;
if (otherclient->Trade->trade_status == 6)
{
RESETPACKET( pak, 0x7c0 );
// Complete the trade
ADDBYTE( pak, 6 );
ADDWORD( pak, otherclient->clientid );
ADDBYTE( pak, 0 );
thisclient->client->SendPacket( &pak );
RESETPACKET( pak, 0x7c0 );
ADDBYTE( pak, 6 );
ADDWORD( pak, thisclient->clientid );
ADDBYTE( pak, 0 );
otherclient->client->SendPacket( &pak );
// Update the zuly
thisclient->CharInfo->Zulies -= thisclient->Trade->trade_count[0x0a];
otherclient->CharInfo->Zulies -= otherclient->Trade->trade_count[0x0a];
thisclient->CharInfo->Zulies += otherclient->Trade->trade_count[0x0a];
otherclient->CharInfo->Zulies += thisclient->Trade->trade_count[0x0a];
unsigned tucount = 0;
unsigned oucount = 0;
// Begin this clients inventory update
BEGINPACKET( pakt, 0x717 );
ADDQWORD( pakt, thisclient->CharInfo->Zulies );
ADDBYTE( pakt, 0 );
// Begin the other clients inventory update
BEGINPACKET( pako, 0x717 );
ADDQWORD( pako, otherclient->CharInfo->Zulies );
ADDBYTE( pako, 0 );
for (unsigned i=0; i<10; i++)
{
if(thisclient->Trade->trade_count[i] > 0)
{
CItem thisitem = thisclient->items[thisclient->Trade->trade_itemid[i]];
unsigned newslot = otherclient->GetNewItemSlot( thisitem );
if(newslot==0xffff) continue;
thisclient->items[thisclient->Trade->trade_itemid[i]].count -= thisclient->Trade->trade_count[i];
if( thisclient->items[thisclient->Trade->trade_itemid[i]].count<=0)
ClearItem(thisclient->items[thisclient->Trade->trade_itemid[i]]);
otherclient->items[newslot]=thisitem;
otherclient->items[newslot].count = thisclient->Trade->trade_count[i];
ADDBYTE( pakt, (unsigned char)thisclient->Trade->trade_itemid[i] );
ADDWORD( pakt, BuildItemHead( thisclient->items[thisclient->Trade->trade_itemid[i]] ) );
ADDDWORD( pakt, BuildItemData( thisclient->items[thisclient->Trade->trade_itemid[i]] ) );
ADDBYTE( pako, newslot );
ADDWORD( pako, BuildItemHead( otherclient->items[newslot] ) );
ADDDWORD( pako, BuildItemData( otherclient->items[newslot] ) );
tucount++;
oucount++;
}
if(otherclient->Trade->trade_count[i] > 0)
{
CItem thisitem = otherclient->items[otherclient->Trade->trade_itemid[i]];
unsigned newslot = thisclient->GetNewItemSlot( thisitem );
if(newslot==0xffff) continue;
otherclient->items[otherclient->Trade->trade_itemid[i]].count -= otherclient->Trade->trade_count[i];
if( otherclient->items[otherclient->Trade->trade_itemid[i]].count<=0 )
ClearItem( otherclient->items[otherclient->Trade->trade_itemid[i]] );
thisclient->items[newslot]=thisitem;
thisclient->items[newslot].count = otherclient->Trade->trade_count[i];
ADDBYTE( pako, (unsigned char)otherclient->Trade->trade_itemid[i] );
ADDWORD( pako, BuildItemHead( otherclient->items[otherclient->Trade->trade_itemid[i]] ) );
ADDDWORD( pako, BuildItemData( otherclient->items[otherclient->Trade->trade_itemid[i]] ) );
ADDBYTE( pakt, newslot );
ADDWORD( pakt, BuildItemHead( thisclient->items[newslot] ) );
ADDDWORD( pakt, BuildItemData( thisclient->items[newslot] ) );
tucount++;
oucount++;
}
}
// Update itemcount and send
SETBYTE( pakt, 8, tucount );
SETBYTE( pako, 8, oucount );
thisclient->client->SendPacket( &pakt );
otherclient->client->SendPacket( &pako );
thisclient->Trade->trade_status=0;
otherclient->Trade->trade_status=0;
thisclient->saveinventory();
otherclient->saveinventory();
}
break;
case 7:
// TRADE BUSY
break;
case 8:
// TRADE TOO FAR
break;
case 9:
// NOT A VALID TARGET
break;
case 10:
// OUT OF INVENTORY
break;
case 11:
//
default:
break;
}
return true;
}
// Trade action
bool CWorldServer::pakTradeAdd ( CPlayer* thisclient, CPacket* P )
{
if(thisclient->Shop->open)
return true;
BYTE islot = GETBYTE((*P),0);
WORD slotid = GETWORD((*P),1);
DWORD count = GETDWORD((*P),3);
CPlayer* otherclient = GetClientByID( thisclient->Trade->trade_target, thisclient->Position->Map );
if (otherclient == NULL) return true;
BEGINPACKET( pak, 0x7c1 );
ADDBYTE( pak, islot );
if( islot == 0x0a )
{
ADDWORD( pak, 0xccdf );//0xccccccdf );
ADDDWORD( pak, count );
thisclient->Trade->trade_count[islot] = count;
}
else
{
if(islot>0x0a)
return false;
if( count != 0 )
{
if(count>thisclient->items[slotid].count)
return false;
thisclient->Trade->trade_count[islot] = count;
thisclient->Trade->trade_itemid[islot] = slotid;
CItem tmpitem = thisclient->items[slotid]; tmpitem.count = count;
ADDWORD( pak, BuildItemHead( tmpitem ) );
ADDDWORD( pak, BuildItemData( tmpitem ) );
}
else
{
thisclient->Trade->trade_count[islot] = 0;
thisclient->Trade->trade_itemid[islot] = 0;
ADDDWORD( pak, 0 );
ADDDWORD( pak, 0 );
}
}
otherclient->client->SendPacket( &pak );
return true;
}
// Attack skill
bool CWorldServer::pakStartSkill ( CPlayer* thisclient, CPacket* P )
{
if( thisclient->Shop->open || thisclient->Status->Muted!=0xff )
return true;
fPoint thispoint;
unsigned int skillid;
UINT targetid = GETWORD( (*P), 0 );
BYTE skillnum = GETBYTE( (*P), 2 );//skill inventory number
if(thisclient->Session->codedebug) //Debug code
{
SendPM(thisclient, "Skill went to pakStartSkill. Skill number = %i", skillnum);
}
if(skillnum >= MAX_SKILL)
{
Log( MSG_HACK, "Invalid Skill id %i for %s ", skillnum, thisclient->CharInfo->charname );
return false;
}
if (skillnum > 29)
{
skillid = thisclient->askill[skillnum - 30] + thisclient->askilllvl[skillnum - 30];
}
else
{
skillid = thisclient->bskills[skillnum];
}
CMap* map = MapList.Index[thisclient->Position->Map];
CCharacter* character = map->GetCharInMap( targetid );
if(character == NULL) return true;
if(character->IsMonster())
{
BEGINPACKET( pak, 0x79f );
ADDWORD( pak, character->clientid );
ADDWORD( pak, character->Stats->HP );
ADDWORD( pak, 0 );
thisclient->client->SendPacket( &pak );
}
CSkills* thisskill = GetSkillByID( skillid );
if(thisskill == NULL)
return true;
if(thisclient->Session->codedebug) //Debug code
{
SendPM(thisclient, "Skill type = %i target = %i",thisskill->skilltype, thisskill->target);
}
if(!thisclient->canUseSkill(thisskill))
{
SendPM(thisclient, "Sorry. You cannot use that skill");
return true;
}
if(thisskill->target == 9 && !character->IsDead())
{
ClearBattle( thisclient->Battle );
return true;
}
//if( isSkillTargetFriendly( thisskill ) )
//{
// if(thisclient->Session->codedebug) //Debug code
// {
// SendPM(thisclient, "Target is friendly. Action = SKILL_BUFF");
// }
// thisclient->StartAction( character, SKILL_BUFF, skillid );
//}
//else
//{
switch(thisskill->skilltype)
{
case 3: case 6:
if(thisclient->Session->codedebug) //Debug code
{
SendPM(thisclient, "Target is UN-friendly. Action = SKILL_ATTACK");
}
thisclient->StartAction( character, SKILL_ATTACK, skillid );
break;
case 9: case 11: case 13:
if(thisclient->Session->codedebug) //Debug code
{
SendPM(thisclient, "Target is either friendly or unfriedly. Action = SKILL_BUFF");
SendPM(thisclient, "My id = %i target id = %i",thisclient->clientid, character->clientid);
}
thisclient->StartAction( character, SKILL_BUFF, skillid );
break;
case 20: // resurrect
ClearBattle( thisclient->Battle );
if(thisskill->target == 9)
{
if(character->IsDead())
{
character->Stats->HP = (int)character->GetMaxHP()/10;
}
return true;
}
break;
default:
SendPM(thisclient, "Unhandled skill request");
break;
}
//}
return true;
}
// Self skills
bool CWorldServer::pakSkillSelf( CPlayer* thisclient, CPacket* P )
{
if(thisclient->Session->codedebug) //Debug code
{
char buffer[200];
sprintf ( buffer, "Skill went to pakSkillSelf" );
SendPM(thisclient, buffer);
}
if( thisclient->Shop->open || thisclient->Status->Muted!=0xff || !thisclient->Status->CanCastSkill)
return true;
unsigned int skillid;
BYTE num = GETBYTE((*P),0);
if(num >= MAX_SKILL)
{
Log( MSG_HACK, "Invalid Skill id %i for %s ", num, thisclient->CharInfo->charname );
return false;
}
if (num > 29)
{
skillid = thisclient->askill[num-30]+thisclient->askilllvl[num-30];
}
else
{
skillid = thisclient->bskills[num];
}
CSkills* thisskill = GetSkillByID( skillid );
if(thisskill == NULL)
return true;
if(thisclient->Session->codedebug) //Debug code
{
char buffer[200];
sprintf ( buffer, "Skill type = %i target = %i",thisskill->skilltype,thisskill->target);
SendPM(thisclient, buffer);
}
if(!thisclient->canUseSkill(thisskill))
{
SendPM(thisclient, "Sorry. You cannot use that skill");
return true;
}
unsigned int skilltarget = thisskill->target;
unsigned int skillrange = thisskill->aoeradius;
if( thisskill->aoe == 0 )
{
if(thisclient->Session->codedebug) //Debug code
{
SendPM(thisclient, "Skill aoe is 0. Action = BUFF_SELF");
}
thisclient->StartAction( NULL, BUFF_SELF, skillid );
}
else
{
if(isSkillTargetFriendly( thisskill ))
{
if(thisclient->Session->codedebug) //Debug code
{
SendPM(thisclient, "Skill aoe is 1 and target is friendly. Action = BUFF_AOE");
}
thisclient->StartAction( NULL, BUFF_AOE, skillid );
}
else
{
if(thisclient->Session->codedebug) //Debug code
{
SendPM(thisclient, "Skill aoe is 1 and target is UN-friendly. Action = SKILL_AOE");
}
thisclient->StartAction( NULL, SKILL_AOE, skillid );
}
}
return true;
}
// Aoe Skill
bool CWorldServer::pakSkillAOE( CPlayer* thisclient, CPacket* P)
{
if(thisclient->Session->codedebug) //Debug code
{
char buffer[200];
sprintf ( buffer, "Skill went to pakSkillAOE" );
SendPM(thisclient, buffer);
}
if( thisclient->Shop->open || thisclient->Status->Muted != 0xff || !thisclient->Status->CanCastSkill) return true;
BYTE num = GETBYTE( (*P), 0 );
thisclient->Position->skilltargetpos.x = P->GetFloat(1)/100; //these set an absolute aoe center. not a monster.
thisclient->Position->skilltargetpos.y = P->GetFloat(5)/100;
if(thisclient->Session->codedebug) //Debug code
{
SendPM(thisclient, "target X = %f target Y = %f",thisclient->Position->skilltargetpos.x,thisclient->Position->skilltargetpos.y );
}
//arnold
if(num >= MAX_SKILL)
{
Log( MSG_HACK, "Invalid Skill id %i for %s ", num, thisclient->CharInfo->charname );
return false;
}
unsigned int skillid;
if (num > 29)
{
skillid = thisclient->askill[num-30] + thisclient->askilllvl[num-30];
}
else
{
skillid = thisclient->bskills[num];
}
CSkills* thisskill = GetSkillByID( skillid );
if(thisskill == NULL) return true;
if(thisclient->Session->codedebug) //Debug code
{
char buffer[200];
sprintf ( buffer, "Skill type = %i target = %i",thisskill->skilltype,thisskill->target);
SendPM(thisclient, buffer);
}
if(!thisclient->canUseSkill(thisskill))
{
SendPM(thisclient, "Sorry. You cannot use that skill");
return true;
}
if(thisskill->aoe == 1)
{
if(isSkillTargetFriendly( thisskill ))
{
if(thisclient->Session->codedebug) //Debug code
{
SendPM(thisclient, "Skill aoe is 1 and target is friendly. Action = nothing");
}
//cout << "Friendly skill: " << thisclient->Battle->skillid << endl;
}
else
{
if(thisclient->Session->codedebug) //Debug code
{
SendPM(thisclient, "Skill aoe is 1 and target is UN-friendly. Action = AOE_TARGET");
}
thisclient->StartAction( NULL , AOE_TARGET, skillid );
}
}
else
{
if(thisclient->Session->codedebug) //Debug code
{
SendPM(thisclient, "Skill aoe is 0. Action = nothing");
}
Log( MSG_INFO, "no aoe, skillid = %i ", thisclient->Battle->skillid);
}
return true;
}
// Consumible Items
bool CWorldServer::pakUseItem ( CPlayer* thisclient, CPacket* P )
{
if(thisclient->Shop->open)
return true;
BYTE slot = GETBYTE((*P),0);
if(!CheckInventorySlot( thisclient, slot))
return false;
if( thisclient->items[slot].count<=0 )
return true;
CUseInfo* thisuse = GetUseItemInfo( thisclient, slot);
if(thisuse == NULL)
{
Log(MSG_WARNING,"[%i]Invalid Item, Item: %i. - Type: %i",
thisclient->clientid, thisclient->items[slot].itemnum,
thisclient->items[slot].itemtype);
return true;
}
bool flag = false;
switch(thisuse->usescript)
{
case 1: // Food
{
thisclient->UsedItem->usevalue = thisuse->usevalue;
thisclient->UsedItem->usetype = thisuse->usetype;
thisclient->UsedItem->userate = 15;
thisclient->UsedItem->used = 0;
BEGINPACKET( pak,0x7a3 );
ADDWORD ( pak, thisclient->clientid );
ADDWORD ( pak, thisuse->itemnum );
SendToVisible( &pak, thisclient );
flag = true;
Log(MSG_WARNING, "Food item used. type %i Value %i", thisuse->usetype, thisuse->usevalue );
}
break;
case 2: // Return Scroll
{
BEGINPACKET( pak,0x7a3 );
ADDWORD ( pak,thisclient->clientid );
ADDWORD ( pak, thisuse->itemnum );
ADDBYTE ( pak,slot );
thisclient->client->SendPacket( &pak );
//thisclient->items[slot].count -= 1;
//if( thisclient->items[slot].count == 0 )
// ClearItem( thisclient->items[slot] );
fPoint thispoint;
thispoint.x = floor( (double)thisuse->usevalue/10000 );
thispoint.y = floor( (double)(thisuse->usevalue%10000) );
TeleportTo ( thisclient, thisuse->usetype, thispoint );
flag = true;
}
break;
case 3: // Charm Scroll
{
CSkills* thisskill = GetSkillByID( thisuse->usetype );
if(thisskill == NULL)
{
Log(MSG_WARNING, "Char %s tried to use invalid scroll type: %i", thisclient->CharInfo->charname, thisuse->usetype );
delete thisuse;
return true;
}
int skilltarget = thisskill->target;
int skillrange = thisskill->aoeradius;
if( thisskill->aoe == 0 )
{
thisclient->StartAction( NULL,BUFF_SELF,thisuse->usetype );
}
else
{
if(isSkillTargetFriendly( thisskill ))
{
thisclient->StartAction( NULL,BUFF_AOE,thisuse->usetype );
}
else
{
thisclient->StartAction( NULL,SKILL_AOE,thisuse->usetype );
}
}
flag = true;
}
break;
case 4: // Dance Scroll | FireCrackers | Emotion
{
//Start Animation
BEGINPACKET( pak, 0x7b2 );
ADDWORD ( pak, thisclient->clientid );
ADDWORD ( pak, thisuse->usevalue );
SendToVisible( &pak, thisclient );
//Finish Animation
RESETPACKET( pak, 0x7bb );
ADDWORD ( pak, thisclient->clientid );
SendToVisible( &pak, thisclient );
//????
RESETPACKET( pak, 0x7b9);
ADDWORD ( pak, thisclient->clientid);
ADDWORD ( pak, thisuse->usevalue );
SendToVisible( &pak, thisclient );
flag = true;
}
break;
case 12: //Dance scrolls
{
CSkills* thisskill = GetSkillByID( thisuse->usetype );
if(thisskill == NULL)
{
Log(MSG_WARNING, "Char %s tried to use invalid Dance scroll type: %i", thisclient->CharInfo->charname, thisuse->usetype );
delete thisuse;
return true;
}
//Log(MSG_INFO, "Char %s used a Dance scroll type: %i", thisclient->CharInfo->charname, thisuse->usetype );
int skilltarget = thisskill->target;
int skillrange = thisskill->aoeradius;
flag = true;
//Log(MSG_INFO, "Sending skill request. AOE range = %i", skillrange);
if(skillrange > 0 ) //AOE effect
{
thisclient->StartAction( NULL,BUFF_AOE,thisuse->usetype );
}
else
{
thisclient->StartAction( NULL,BUFF_SELF,thisuse->usetype );
}
flag = true;
}
break;
case 13: // Fireworks
{
CSkills* thisskill = GetSkillByID( thisuse->usetype );
if(thisskill == NULL)
{
Log(MSG_WARNING, "Char %s tried to use invalid Dance scroll type: %i", thisclient->CharInfo->charname, thisuse->usetype );
delete thisuse;
return true;
}
//Log(MSG_INFO, "Char %s used a Dance scroll type: %i", thisclient->CharInfo->charname, thisuse->usetype );
int skilltarget = thisskill->target;
int skillrange = thisskill->aoeradius;
flag = true;
Log(MSG_INFO, "Sending skill request. AOE range = %i", skillrange);
if(skillrange > 0 ) //AOE effect
{
thisclient->StartAction( NULL,BUFF_AOE,thisuse->usetype );
}
else
{
Log(MSG_INFO, "Char %s used an invalid firework type: %i", thisclient->CharInfo->charname, thisuse->usetype );
}
flag = true;
}
break;
case 5: // summon
case 11: // Summon ownerless
{
CNPCData* thisnpc = GetNPCDataByID( thisuse->usevalue );
if(thisnpc == NULL)
{
Log( MSG_WARNING,"[%i]NPCDATA NOT Founded: %i.",
thisclient->clientid,thisuse->usevalue );
delete thisuse;
return true;
}
//Start Animation
BEGINPACKET( pak, 0x7b2 );
ADDWORD ( pak, thisclient->clientid );
ADDWORD ( pak, thisuse->usetype );
ADDBYTE ( pak, 6 );
SendToVisible( &pak, thisclient );
//Finish Animation
RESETPACKET( pak, 0x7bb );
ADDWORD ( pak, thisclient->clientid );
SendToVisible( &pak, thisclient );
//????
RESETPACKET( pak, 0x7b9);
ADDWORD ( pak, thisclient->clientid);
ADDWORD ( pak, thisuse->usetype );
SendToVisible( &pak, thisclient );
// Add our Mob to the mobs list
fPoint position = RandInCircle( thisclient->Position->current, 5 );
CMap* map = MapList.Index[thisclient->Position->Map];
int owner = 0;
if(thisuse->usescript == 5) owner = thisclient->clientid;
map->AddMonster( thisuse->usevalue, position, owner,0,1 );
flag = true;
}
break;
case 6: // Snowball
{
WORD clientid = GETWORD((*P),2);
fPoint thispoint;
CMap* map = MapList.Index[thisclient->Position->Map];
CCharacter* character = map->GetCharInMap( clientid );
if(character == NULL) return true;
thisclient->StartAction( character, SKILL_BUFF, thisuse->usevalue );
flag = true;
}
break;
case 7: // scrolls [damage,maxhp,...]
{
CSkills* thisskill = GetSkillByID( thisuse->usetype );
if(thisskill == NULL)
{
Log(MSG_WARNING, "Char %s tried to use invalid scroll type: %i", thisclient->CharInfo->charname, thisuse->usetype );
delete thisuse;
return true;
}
int skilltarget = thisskill->target;
int skillrange = thisskill->aoeradius;
if( thisskill->aoe == 0 )
{
thisclient->StartAction( NULL, BUFF_SELF, thisuse->usetype );
}
else
{
if(isSkillTargetFriendly( thisskill ))
{
thisclient->StartAction( NULL, BUFF_AOE, thisuse->usetype );
}
else
{
thisclient->StartAction( NULL, SKILL_AOE, thisuse->usetype );
}
}
flag = true;
}
break;
case 10: // Skill Book
{
flag = LearnSkill( thisclient, thisuse->usevalue );
}
break;
case 14: // Fairy scroll
{
GServer->Config.ScrollFairy ++; //increase count of scroll fairies by one
int oldFairyMax = GServer->Config.FairyMax;
GServer->Config.FairyMax = (int)ceil((float)GServer->ClientList.size() / 50.0) + GServer->Config.ScrollFairy; //recalculate the maximum number of fairies
if( oldFairyMax < GServer->Config.FairyMax ) // if we increased the fairy max we need to make a dummy fairy to hold the space or we will crash the server
{
CFairy* thisfairy = new (nothrow) CFairy;
thisfairy->LastTime = clock();
thisfairy->assigned = 0;
thisfairy->ListIndex = 0;
thisfairy->WaitTime = GServer->Config.FairyWait;
GServer->FairyList.push_back( thisfairy );
}
for (int i=0; i<Config.FairyMax; i++) // Now we check all fairies to find an unasigned one
{
if(FairyList.at(i)->assigned == false) // we found an empty fairy so let's assign it
{
FairyList.at(i)->ListIndex = 0;
FairyList.at(i)->LastTime = clock();
FairyList.at(i)->assigned = true;
FairyList.at(i)->scroll = true; // Scroll value set to true. this IS a scroll buff fairy
thisclient->Fairy = true;
thisclient->FairyListIndex = i; // FairyList index number of our actual fairy
DoFairyStuff(thisclient, 1); // spawn fairy to target
thisclient->SetStats();
flag = true;
break;
}
}
break;
}
}
if(flag == true)
{
BEGINPACKET( pak,0x7a3 );
ADDWORD ( pak, thisclient->clientid );
ADDWORD ( pak, thisuse->itemnum );
ADDBYTE ( pak, slot );
thisclient->client->SendPacket( &pak );
thisclient->items[slot].count -= 1;
if( thisclient->items[slot].count <= 0 )
ClearItem( thisclient->items[slot] );
thisclient->saveinventory();
}
delete thisuse;
return true;
}
// Level UP Skill
bool CWorldServer::pakLevelUpSkill( CPlayer *thisclient, CPacket* P )
{
CSkills* thisskill;
CSkills* nextskill;
char rs = 0;
char rl = 0;
int pos = GETBYTE ((*P),0);
// Check that skill is valid
if (pos > 59)
{ // Passive Skill - ID + 60
thisskill = GetSkillByID((thisclient->pskill[pos-60])+(thisclient->pskilllvl[pos-60]));
nextskill = GetSkillByID(((thisclient->pskill[pos-60])+(thisclient->pskilllvl[pos-60]))+1);
}
else if (pos > 29)
{ // Active Skill - ID + 30
thisskill = GetSkillByID((thisclient->askill[pos-30])+(thisclient->askilllvl[pos-30]));
nextskill = GetSkillByID(((thisclient->askill[pos-30])+(thisclient->askilllvl[pos-30]))+1);
}
else return true;
// Make sure skill is found
if (thisskill == NULL || nextskill == NULL) return true;
if(thisskill->skillid != nextskill->skillid) return true; //if skillid is different then we have gone off the end of the skill levels
// Check SP requirement
if (thisclient->CharInfo->SkillPoints < nextskill->sp) {
BEGINPACKET( pak, 0x7b1 );
ADDBYTE( pak, 0x02 );
thisclient->client->SendPacket( &pak );
return true;
}
// Check zuly requirement
if (thisclient->CharInfo->Zulies < nextskill->zuly) {
BEGINPACKET( pak, 0x7b1 );
ADDBYTE( pak, 0x01 );
thisclient->client->SendPacket( &pak );
return true;
}
// Check both stat requirements.
bool fail = false;
for (char i = 0; i < 2; i++)
{
switch (nextskill->req[i])
{
case sLevel:
if (nextskill->reqam[i] > thisclient->Stats->Level) fail = true;
break;
case sStrength:
if (nextskill->reqam[i] > thisclient->Attr->Str) fail = true;
break;
case sDexterity:
if (nextskill->reqam[i] > thisclient->Attr->Dex) fail = true;
break;
case sIntelligence:
if (nextskill->reqam[i] > thisclient->Attr->Int) fail = true;
break;
case sConcentration:
if (nextskill->reqam[i] > thisclient->Attr->Con) fail = true;
break;
case sCharm:
if (nextskill->reqam[i] > thisclient->Attr->Cha) fail = true;
break;
case sSensibility:
if (nextskill->reqam[i] > thisclient->Attr->Sen) fail = true;
break;
default:
break;
}
}
if (fail)
{
BEGINPACKET( pak, 0x7b1 );
ADDBYTE( pak, 0x03 );
thisclient->client->SendPacket( &pak );
return true;
}
// Check class requirement
bool passClass = false;
int nocheck = 4; // Used to check if no lvl check
for (char i = 0; i < 4; i++)
{
if (nextskill->c_class[i]>0)
{
switch(nextskill->c_class[i])
{
case cSoldierJob:
if((thisclient->CharInfo->Job)/100==1)passClass = true;
break;
case cMuseJob:
if((thisclient->CharInfo->Job)/100==2)passClass = true;
break;
case cHawkerJob:
if((thisclient->CharInfo->Job)/100==3)passClass = true;
break;
case cDealerJob:
if((thisclient->CharInfo->Job)/100==4)passClass = true;
break;
case cKnightJob:
if(thisclient->CharInfo->Job==121)passClass = true;
break;
case cChampionJob:
if(thisclient->CharInfo->Job==122)passClass = true;
break;
case cMageJob:
if(thisclient->CharInfo->Job==221)passClass = true;
break;
case cClericJob:
if(thisclient->CharInfo->Job==222)passClass = true;
break;
case cRaiderJob:
if(thisclient->CharInfo->Job==321)passClass = true;
break;
case cScoutJob:
if(thisclient->CharInfo->Job==322)passClass = true;
break;
case cBourgeoisJob:
if(thisclient->CharInfo->Job==421)passClass = true;
break;
case cArtisanJob:
if(thisclient->CharInfo->Job==422)passClass = true;
break;
default:
break;
}
if (passClass) break;
} else
nocheck--;
}
// Player isn't the required class/job
if (!passClass && nocheck > 0)
{
BEGINPACKET( pak, 0x7b1 );
ADDBYTE( pak, 0x04 );
thisclient->client->SendPacket( &pak );
return true;
}
if(thisclient->Session->codedebug) //Debug code
{
char buffer[200];
sprintf ( buffer, "Passed check for class" );
SendPM(thisclient, buffer);
}
// Check required skills/skill levels
for (char j = 0; j < 3 ; j++)
{
if(nextskill->rskill[j]>0)
{
rs++;
for (char i = 0; i<30;i++)
{
// Subtract 1 because our characters levels are actually off by 1
// Check passive skill
if ( ( thisclient->pskill[i] == nextskill->rskill[j] ) &&
( thisclient->pskilllvl[i] >= nextskill->lskill[j] - 1 ) )
{
rl++;
break; // No use continueing for the rest of the for loop, right?
}
// Check Active Skill
if ( ( thisclient->askill[i] == nextskill->rskill[j] ) &&
( thisclient->askilllvl[i] >= nextskill->lskill[j] - 1 ) )
{
rl++;
break; // No need to continue inner loop
}
}
}
}
if(rl != rs)
{
BEGINPACKET( pak, 0x7b1 );
ADDBYTE( pak, 0x05 );
thisclient->client->SendPacket( &pak );
return true;
}
if (pos > 59) thisclient->pskilllvl[pos-60] += 1;
else if (pos > 29) thisclient->askilllvl[pos-30] += 1;
thisclient->CharInfo->SkillPoints -= nextskill->sp;
thisclient->CharInfo->Zulies -= nextskill->zuly;
BEGINPACKET( pak, 0x7b1 );
ADDBYTE( pak, 0x00 );
ADDBYTE( pak, GETBYTE ((*P),0) );
ADDWORD( pak, GETWORD ((*P),1) );
ADDWORD( pak, thisclient->CharInfo->SkillPoints );
thisclient->client->SendPacket( &pak );
thisclient->SetStats();
return true;
}
// Equip bullets arrows and cannons
bool CWorldServer::pakEquipABC ( CPlayer* thisclient, CPacket* P )
{
if(thisclient->Shop->open)
return true;
BYTE itemslot = GETBYTE((*P),0);
int slot = ((itemslot-32)/4)+72;
int dest = 0;
int type = (itemslot-32)%4;
if(!CheckInventorySlot( thisclient, slot))
return false;
if(itemslot>3)
{
dest = type+132;
}
else
{
slot = itemslot + 132;
dest = thisclient->GetNewItemSlot( thisclient->items[slot] );
if(dest==0xffff)
return true;
type=300;
}
CItem tmpitm = thisclient->items[slot];
thisclient->items[slot] =thisclient->items[dest];
thisclient->items[dest] = tmpitm;
thisclient->UpdateInventory( dest, slot );
BEGINPACKET( pak, 0x7ab );
ADDWORD ( pak, thisclient->clientid );
unsigned int effect = ( thisclient->items[dest].itemnum * 32 ) + type;
ADDWORD ( pak, effect );
SendToVisible( &pak, thisclient );
thisclient->Stats->Attack_Power = thisclient->GetAttackPower( );
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Craft item (Template by Arnold) (Crafting modifications by: Killerfly) Fixed for irose by: Arnold //
// Recoded for osProse by PurpleYouko //
//////////////////////////////////////////////////////////////////////////////////////////////////////////
bool CWorldServer::pakCraft( CPlayer* thisclient, CPacket* P )
{
if(thisclient->Shop->open==true)
return true;
CItem item;
UINT quality = 0;
int m = 0;
// determine the item number and type
item.itemnum = (GETWORD((*P), 2));
item.itemtype = (GETBYTE((*P), 0x1));
//get material used lookup number
int materialnumber = 0;
if(item.itemtype < 10)
{
materialnumber = EquipList[item.itemtype].Index[item.itemnum]->material;
}
else
{
switch(item.itemtype)
{
case 11:materialnumber = JemList.Index[item.itemnum]->material;break;
case 14:materialnumber = PatList.Index[item.itemnum]->material;break;
default:
break;
}
}
if(thisclient->Session->codedebug)
{
SendPM(thisclient, "Attempting to craft an item. type = %i. id = %i",item.itemtype, item.itemnum);
SendPM(thisclient, "Material number = %i",materialnumber);
}
//check material slots before we start making the new item
if(ProductList.Index[materialnumber]->matType != 0) // recipe has an item type listed rather than a specific item
{
WORD material= GETWORD((*P), 4);
UINT matid = thisclient->items[material].itemnum;
quality = NaturalList.Index[matid]->quality;
if(thisclient->Session->codedebug)
{
SendPM(thisclient, "Recipe recquires an item with type = %i.",ProductList.Index[materialnumber]->matType);
SendPM(thisclient, "Type of material in slot = %i",thisclient->items[material].type);
}
if(ProductList.Index[materialnumber]->matType != thisclient->items[material].type)
{
if(thisclient->Session->codedebug)
{
SendPM(thisclient, "Rejected as mat types do not match");
}
return true; //item in the slot is the wrong type
}
}
m=0;
for(char used=4; used != 12; used +=2)
{
WORD material= GETWORD((*P), used);//gets inventory location
if(thisclient->Session->codedebug)
{
SendPM(thisclient, "Slot number = %i", material);
SendPM(thisclient, "Recipe recquires an item with type = %i. id = %i",ProductList.Index[materialnumber]->itemtype[m],ProductList.Index[materialnumber]->itemid[m]);
SendPM(thisclient, "Type of material in slot = %i. id = %i",thisclient->items[material].itemtype,thisclient->items[material].itemnum);
SendPM(thisclient, "Material count required = %i", ProductList.Index[materialnumber]->amount[m]);
SendPM(thisclient, "Material count in slot = %i", thisclient->items[material].count);
}
if(!CheckInventorySlot( thisclient, material))
{
SendPM(thisclient, "Crafting Error 0: Missing or incorrect material in inventory slot.");
return true;
}
if (material != 0)
{
if(ProductList.Index[materialnumber]->matType != 0 && m == 0) //only checked for the first item in the recipe
{
if(thisclient->items[material].type != ProductList.Index[materialnumber]->matType)
{
SendPM(thisclient, "Crafting Error %i 1: Server and Client crafting recipes do not match",m);
return true; // item type does not match recipe
}
}
else
{
if(thisclient->items[material].itemtype != ProductList.Index[materialnumber]->itemtype[m])
{
SendPM(thisclient, "Crafting Error %i 2: Server and Client crafting recipes do not match",m);
return true; // item type does not match recipe
}
if(thisclient->items[material].itemnum != ProductList.Index[materialnumber]->itemid[m])
{
SendPM(thisclient, "Crafting Error %i 3: Server and Client crafting recipes do not match",m);
return true; // item id does not match recipe
}
}
if(thisclient->items[material].count < ProductList.Index[materialnumber]->amount[m])
{
SendPM(thisclient, "Crafting Error %i 4: Server and Client crafting recipes do not match",m);
return true; //not enough of the required item
}
}
m += 1;
}
if(thisclient->Session->codedebug)
{
SendPM(thisclient, "Item cleared the checks and will be created");
}
// item durability randomizer
int lowest = thisclient->Attr->Con/ 10 + 17;
int highest = thisclient->Attr->Con / 10 + 70;
int range = (highest - lowest) + 1;
item.durability = lowest+int(range*rand()/(RAND_MAX + 1.0));
// stats randomizer
int changeofstatslow = thisclient->Attr->Sen / 13 + 10;
int changeofstatshigh = thisclient->Attr->Sen / 13 + 50;
int changeofstatsrange = (changeofstatshigh-changeofstatslow)+1;
if (changeofstatslow+int(changeofstatsrange*rand()/(RAND_MAX + 1.0)) > 50)
{
int statslowget = 1;
int statshighget = 256;
int setstatrange=(statshighget-statslowget)+1;
item.stats = statslowget + int(setstatrange*rand()/(RAND_MAX + 1.0));
item.appraised = 1;
}
else
{
item.stats = 0;
item.appraised = 0;
}
item.socketed = 0;
item.gem = 0;
item.lifespan = 100; //Its new so 100%
item.refine = 0;
item.count = 1;
unsigned newslot= thisclient->GetNewItemSlot( item );
if (newslot !=0xffff)
{
//removes material items from the slots
item.count +=(thisclient->items[newslot].count);
thisclient->items[newslot] = item;
m=0;
for(char used=4; used != 12; used +=2)
{
WORD material= GETWORD((*P), used);//gets inventory location
if (material != 0)
{
thisclient->items[material].count -= ProductList.Index[materialnumber]->amount[m];
m += 1;
if (thisclient->items[material].count <=0)
{
ClearItem(thisclient->items[material]);
}
}
}
BEGINPACKET( pak, 0x07d8);
ADDWORD( pak, thisclient->clientid );
ADDWORD( pak, 0x0100);
ADDWORD( pak, item.itemnum);// item id not shifted
thisclient->client->SendPacket(&pak);
RESETPACKET( pak, 0x07af);
ADDBYTE( pak, 0x00);
ADDWORD( pak, newslot);
// Make craft bars
int bar1 = item.durability * 9;
int bar2 = changeofstatsrange * 9;
int bar3 = item.durability + changeofstatsrange * 6;
int bar4 = item.durability + changeofstatsrange + bar3 / 3;
ADDWORD( pak, bar1);//progress bar1 0 is empty 0x0400 is full bar
ADDWORD( pak, bar2);//progress bar2 0 is empty 0x0400 is full bar
if ((GETWORD((*P), 8))==0){ ADDWORD( pak, 0x99a0);}else{ ADDWORD( pak, bar3);}//progress bar3 0 is empty 0x0400 is full bar
if ((GETWORD((*P), 10))==0){ ADDWORD( pak, 0x99a0);}else{ ADDWORD( pak, bar4);}//progress bar4 0 is empty 0x0400 is full bar
ADDWORD(pak, BuildItemHead(item));
if (item.itemtype == 11)
{
ADDWORD( pak, item.count);// amount
ADDWORD( pak, 0x0000);
}
else
{
ADDDWORD(pak, BuildItemData(item));
}
int crafting_exp = item.durability + changeofstatsrange * (thisclient->Stats->Level/ 5);
thisclient->CharInfo->Exp += crafting_exp;// add exp
thisclient->client->SendPacket(&pak);
if(!thisclient->CheckPlayerLevelUP( )){
RESETPACKET( pak, 0x79b );
ADDDWORD ( pak, thisclient->CharInfo->Exp );
ADDWORD ( pak, thisclient->CharInfo->stamina );
ADDWORD ( pak, 0 );
thisclient->client->SendPacket( &pak );}
}
else
{
BEGINPACKET (pak, 0x702);
ADDSTRING(pak, "No free slot !");
ADDBYTE(pak, 0);
thisclient->client->SendPacket(&pak);
}
thisclient->saveinventory();
return true;
}
bool CWorldServer::pakModifiedItemDone( CPlayer* thisclient, CPacket* P )
{
DWORD result = GETDWORD((*P), 0x00 );
BEGINPACKET( pak, 0x07d8);
ADDWORD( pak, thisclient->clientid );
ADDDWORD( pak, result);
SendToVisible( &pak , thisclient);
return true;
}
// Identify Item
bool CWorldServer::pakidentify( CPlayer* thisclient, CPacket* P)
{
WORD itemslot = GETWORD ((*P),0);
if(!CheckInventorySlot( thisclient, itemslot))
return false;
thisclient->items[itemslot].appraised = true;
BEGINPACKET( pak, 0x7ba );
ADDWORD ( pak, itemslot );
ADDBYTE ( pak, 0x00 );
thisclient->client->SendPacket( &pak );
return true;
}
// Show Storge Items
bool CWorldServer::pakStorage( CPlayer* thisclient, CPacket* P)
{
BYTE action = GETBYTE((*P),0);
switch(action)
{
case 0x00:
{
UINT nstorageitems = thisclient->Getnstorageitems(thisclient);
Log( MSG_INFO, "Number of items in storage: %i ", nstorageitems);
BEGINPACKET( pak, 0x7ad );
ADDBYTE ( pak, 0x00 );
ADDBYTE ( pak, nstorageitems ); //numero de items
UINT counter = 0;
for(int i=0;i<160;i++)
{
if( thisclient->storageitems[i].itemtype !=0 && counter < 144) //packet can only handle 144 items
{
ADDBYTE ( pak, i );
ADDWORD ( pak, BuildItemHead( thisclient->storageitems[i] ) );
ADDDWORD ( pak, BuildItemData( thisclient->storageitems[i] ) );
counter ++;
}
}
ADDQWORD( pak, thisclient->CharInfo->Storage_Zulies );
thisclient->client->SendPacket( &pak );
}
break;
default:
Log( MSG_INFO, "Storage unknow action: %i ", action);
}
return true;
}
// Change Storage (Deposit/Withdraw items)
bool CWorldServer::pakChangeStorage( CPlayer* thisclient, CPacket* P)
{
/* Packet for this function
===========================
[BYTE] Action
[BYTE] Item Slot
[WORD] Item Head
[DWORD] Item Body
[BYTE] Unk (0x00)
*/
BYTE action = GETBYTE((*P),0);
switch(action)
{
case 0x00: //Deposit
{
int itemslot = (int)GETBYTE((*P),1);
CItem clientitem = GetItemByHeadAndData( GETWORD((*P), 2), GETDWORD((*P), 4) );
if(!CheckInventorySlot( thisclient, itemslot ))
return false;
CItem newitem = thisclient->items[itemslot];
//if(newitem == NULL)
// return true;
// Set the newitem's count to the count from the client for slot search
newitem.count = clientitem.count;
Log(MSG_INFO, "New Item: %i %i", newitem.itemtype, newitem.itemnum);
// find an empty or matching slot depending on new item type
int newslot = thisclient->GetNewStorageItemSlot ( newitem );
if(newslot == 0xffff)
return true;
if(newitem.itemtype >= 10 && newitem.itemtype <= 12) //is it a stackable type
{
int count = clientitem.count;
if(count > thisclient->items[itemslot].count)
count = thisclient->items[itemslot].count; //stops players transferring more than they actually have
newitem.count = count;
if (thisclient->storageitems[newslot].count > 0)
thisclient->storageitems[newslot].count += newitem.count; //add the new items to the storage slot
else
thisclient->storageitems[newslot] = newitem;
thisclient->items[itemslot].count -= count; //delete the items from inventory slot
if(thisclient->items[itemslot].count <= 0)
ClearItem(thisclient->items[itemslot]);
}
else
{
// non-stackable
ClearItem(thisclient->items[itemslot]);
thisclient->storageitems[newslot] = newitem;
}
BEGINPACKET( pak, 0x7ae );
ADDWORD ( pak, itemslot );
ADDWORD ( pak, newslot );
ADDWORD ( pak, BuildItemHead( thisclient->items[itemslot] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[itemslot] ) );
ADDWORD ( pak, BuildItemHead( thisclient->storageitems[newslot] ) );
ADDDWORD ( pak, BuildItemData( thisclient->storageitems[newslot] ) );
ADDQWORD ( pak, thisclient->CharInfo->Zulies );
ADDBYTE ( pak, 0x00 );
thisclient->client->SendPacket( &pak );
//thisclient->nstorageitems++; //this is pointless and serves no purpose
}
break;//thanks to anon for post that this break was missing
case 0x01: //Withdraw
{
BYTE storageslot = GETBYTE((*P),1);
CItem clientitem = GetItemByHeadAndData( GETWORD((*P), 2), GETDWORD((*P), 4) );
if(storageslot >= 160)
{
Log( MSG_HACK, "Invalid storage slot %i from %s", storageslot, thisclient->Session->username );
return false;
}
CItem newitem = thisclient->storageitems[storageslot];
newitem.count = clientitem.count;
int newslot= thisclient->GetNewItemSlot ( newitem );
if (newslot == 0xffff)
return true;
if(newitem.itemtype > 9 && newitem.itemtype < 14)
{
WORD count = clientitem.count;
if( count > thisclient->storageitems[storageslot].count )
count = thisclient->storageitems[storageslot].count;
newitem.count = count;
if (thisclient->items[newslot].count > 0)
thisclient->items[newslot].count += newitem.count;
else
thisclient->items[newslot] = newitem;
thisclient->storageitems[storageslot].count -= count;
if(thisclient->storageitems[storageslot].count<=0)
ClearItem(thisclient->storageitems[storageslot]);
}
else
{
ClearItem(thisclient->storageitems[storageslot]);
thisclient->items[newslot] = newitem;
}
BEGINPACKET( pak, 0x7ae );
ADDWORD ( pak, newslot );
ADDWORD ( pak, storageslot );
ADDWORD ( pak, BuildItemHead( thisclient->items[newslot] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[newslot] ) );
ADDWORD ( pak, BuildItemHead( thisclient->storageitems[storageslot] ) );
ADDDWORD ( pak, BuildItemData( thisclient->storageitems[storageslot] ) );
ADDQWORD ( pak, thisclient->CharInfo->Zulies );
ADDBYTE ( pak, 0x00 );
thisclient->client->SendPacket( &pak );
//thisclient->nstorageitems--; //this is pointless and serves no purpose
}
break;
default:
Log( MSG_INFO, "Storage unknow action: %i ", action);
}
thisclient->saveinventory();
thisclient->savestorage();
return true;
}
// Deposit/Widthdraw zulies
bool CWorldServer::pakStoreZuly( CPlayer* thisclient, CPacket* P)
{
BYTE action = GETBYTE ((*P), 0 );
QWORD zuly = GETQWORD ((*P), 1 );
switch(action)
{
case 0x10://deposit'
{
if(zuly > thisclient->CharInfo->Zulies)
return true;
thisclient->CharInfo->Zulies -= zuly;
thisclient->CharInfo->Storage_Zulies += zuly;
BEGINPACKET( pak, 0x7da );
ADDQWORD ( pak, thisclient->CharInfo->Zulies );
ADDQWORD ( pak, thisclient->CharInfo->Storage_Zulies );
ADDBYTE ( pak, 0x00 );
thisclient->client->SendPacket( &pak );
}
break;
case 0x11://withdraw
{
if(zuly > thisclient->CharInfo->Storage_Zulies )
return true;
thisclient->CharInfo->Zulies += zuly;
thisclient->CharInfo->Storage_Zulies -= zuly;
BEGINPACKET( pak, 0x7da );
ADDQWORD ( pak, thisclient->CharInfo->Zulies );
ADDQWORD ( pak, thisclient->CharInfo->Storage_Zulies );
ADDBYTE ( pak, 0x00 );
thisclient->client->SendPacket( &pak );
}
break;
default:
{
Log( MSG_INFO, "Storage unknow action: %i ", action);
break;
}
}
thisclient->saveinventory();
thisclient->savestorage();
return true;
}
// Open Shop
bool CWorldServer::pakOpenShop( CPlayer* thisclient, CPacket* P )
{
//Log( MSG_INFO, "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x ", GETBYTE((*P),0), GETBYTE((*P),1), GETBYTE((*P),2), GETBYTE((*P),3), GETBYTE((*P),4), GETBYTE((*P),5), GETBYTE((*P),6), GETBYTE((*P),7), GETBYTE((*P),8), GETBYTE((*P),9), GETBYTE((*P),10), GETBYTE((*P),11), GETBYTE((*P),12), GETBYTE((*P),13), GETBYTE((*P),14), GETBYTE((*P),15), GETBYTE((*P),16), GETBYTE((*P),17), GETBYTE((*P),18), GETBYTE((*P),19), GETBYTE((*P),20), GETBYTE((*P),21), GETBYTE((*P),22), GETBYTE((*P),23), GETBYTE((*P),24) );
if( thisclient->Shop->open )
return true;
BYTE nselling = GETBYTE((*P),0);
BYTE nbuying = GETBYTE((*P),1);
if(nselling>30 || nbuying>30)
return true;
int nchar = ((nselling + nbuying) * 11 )+2;
strncpy_s(thisclient->Shop->name ,(char*)&(*P).Buffer[nchar] , P->Size-nchar );
thisclient->Shop->Selling = nselling;
thisclient->Shop->Buying = nbuying;
for(int i=0;i<nselling;i++)
{
int n=(i*11)+2;
BYTE slot = GETBYTE((*P),n);
if(!CheckInventorySlot( thisclient, slot))
return false;
thisclient->Shop->SellingList[i].slot = slot;
if( thisclient->items[slot].itemtype>9 && thisclient->items[slot].itemtype<14 )
thisclient->Shop->SellingList[i].count = GETWORD((*P),n+3);
else
thisclient->Shop->SellingList[i].count = 1;
thisclient->Shop->SellingList[i].price = GETDWORD((*P),n+7);
}
for(int i=0;i<nbuying;i++)
{
unsigned int n=(nselling*11)+2+(i*11);
BYTE slot = GETBYTE((*P),n);
thisclient->Shop->BuyingList[slot].slot = slot;
DWORD head = GETWORD((*P),n+1);
DWORD data = GETDWORD((*P),n+3);
CItem thisitem = GetItemByHeadAndData( head, data );
thisclient->Shop->BuyingList[slot].item = thisitem;
if( thisitem.itemtype > 9 && thisitem.itemtype < 14 )
thisclient->Shop->BuyingList[slot].count = GETWORD((*P),n+3);
else
thisclient->Shop->BuyingList[slot].count = 1;
thisclient->Shop->BuyingList[slot].price = GETDWORD((*P),n+7);
}
BEGINPACKET( pak, 0x796 );
ADDWORD ( pak, thisclient->clientid );
ADDFLOAT ( pak, thisclient->Position->current.x );
ADDFLOAT ( pak, thisclient->Position->current.y );
ADDWORD ( pak, 0x9057 );//>???
SendToVisible( &pak, thisclient );
RESETPACKET( pak, 0x7c2 );
ADDWORD ( pak, thisclient->clientid );
ADDWORD ( pak, thisclient->Shop->ShopType );
ADDSTRING ( pak, thisclient->Shop->name );
ADDBYTE ( pak, 0x00 );
SendToVisible( &pak, thisclient );
thisclient->Shop->open = true;
return true;
}
// Show Shop to other players
bool CWorldServer::pakShowShop( CPlayer* thisclient, CPacket* P )
{
WORD otherclientid = GETWORD((*P),0);
CPlayer* otherclient = GetClientByID ( otherclientid, thisclient->Position->Map );
if(otherclient == NULL)
return true;
BEGINPACKET( pak, 0x7c4 );
ADDBYTE ( pak, otherclient->Shop->Selling );
ADDBYTE ( pak, otherclient->Shop->Buying );
for(unsigned int i = 0; i<otherclient->Shop->Selling;i++)
{
CItem thisitem = otherclient->items[otherclient->Shop->SellingList[i].slot];
thisitem.count = otherclient->Shop->SellingList[i].count;
ADDBYTE ( pak, i );
ADDWORD ( pak, BuildItemHead( thisitem ) );
ADDDWORD ( pak, BuildItemData( thisitem ) );
ADDDWORD ( pak, otherclient->Shop->SellingList[i].price );
}
for(unsigned int i = 0; i<30;i++)
{
if(otherclient->Shop->BuyingList[i].count>0)
{
CItem thisitem = otherclient->Shop->BuyingList[i].item;
ADDBYTE ( pak, i );
ADDWORD ( pak, BuildItemHead( thisitem ) );
ADDDWORD ( pak, BuildItemData( thisitem ) );
ADDDWORD ( pak, otherclient->Shop->BuyingList[i].price );
}
}
ADDBYTE ( pak, 0x00 );
thisclient->client->SendPacket( &pak );
return true;
}
// Buy From Shop
bool CWorldServer::pakBuyShop( CPlayer* thisclient, CPacket* P )
{
// Log( MSG_INFO, "Size:%04x", P->Size );
// Log( MSG_INFO, "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x ", GETBYTE((*P),0), GETBYTE((*P),1), GETBYTE((*P),2), GETBYTE((*P),3), GETBYTE((*P),4), GETBYTE((*P),5), GETBYTE((*P),6), GETBYTE((*P),7), GETBYTE((*P),8), GETBYTE((*P),9), GETBYTE((*P),10), GETBYTE((*P),11), GETBYTE((*P),12), GETBYTE((*P),13), GETBYTE((*P),14), GETBYTE((*P),15), GETBYTE((*P),16), GETBYTE((*P),17), GETBYTE((*P),18), GETBYTE((*P),19), GETBYTE((*P),20), GETBYTE((*P),21), GETBYTE((*P),22), GETBYTE((*P),23), GETBYTE((*P),24) );
WORD otherclientid = GETWORD((*P),0);
BYTE action = GETBYTE((*P),2);
switch(action)
{
case 0x01://check this
{
CPlayer* otherclient = GetClientByID( otherclientid, thisclient->Position->Map );
if( otherclient == NULL )
return true;
BYTE slot = GETBYTE((*P),3);
unsigned int count = 0;
unsigned int invslot = otherclient->Shop->SellingList[slot].slot;
CItem newitem = otherclient->items[invslot];
if(otherclient->items[invslot].itemtype>9 &&
otherclient->items[invslot].itemtype<14)
count = GETWORD((*P),6);
else
count = 1;
if( count > otherclient->Shop->SellingList[slot].count )
return true;
newitem.count = count;
if( thisclient->CharInfo->Zulies<(otherclient->Shop->SellingList[slot].price*count) )
return true;
unsigned int newslot = thisclient->GetNewItemSlot ( newitem );
if(newslot==0xffff)
return true;
thisclient->CharInfo->Zulies -= (otherclient->Shop->SellingList[slot].price*count);
otherclient->CharInfo->Zulies += (otherclient->Shop->SellingList[slot].price*count);
if(otherclient->items[invslot].itemtype>9 &&
otherclient->items[invslot].itemtype<14)
{
if(otherclient->items[invslot].count<=count)
{
ClearItem(otherclient->items[invslot])
otherclient->Shop->SellingList[slot].slot = 0;
otherclient->Shop->SellingList[slot].count = 0;
otherclient->Shop->SellingList[slot].price = 0;
}
else
{
if(otherclient->Shop->SellingList[slot].count<=count)
{
otherclient->Shop->SellingList[slot].slot = 0;
otherclient->Shop->SellingList[slot].count = 0;
otherclient->Shop->SellingList[slot].price = 0;
}
else
{
otherclient->Shop->SellingList[slot].count -= count;
}
otherclient->items[invslot].count-=count;
}
}
else
{
ClearItem( otherclient->items[invslot] )
otherclient->Shop->SellingList[slot].slot = 0;
otherclient->Shop->SellingList[slot].count = 0;
otherclient->Shop->SellingList[slot].price = 0;
}
if(thisclient->items[newslot].count!=0)
thisclient->items[newslot].count += newitem.count;
else
thisclient->items[newslot] = newitem;
//update inventory (buyer)
BEGINPACKET( pak, 0x7c7 );
ADDQWORD ( pak, thisclient->CharInfo->Zulies );
ADDBYTE ( pak, 0x01 ); //buy action
ADDBYTE ( pak, newslot );
ADDWORD ( pak, BuildItemHead( thisclient->items[newslot] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[newslot] ) );
thisclient->client->SendPacket( &pak );
//update inventory (seller)
RESETPACKET( pak, 0x7c7 );
ADDQWORD ( pak, otherclient->CharInfo->Zulies );
ADDBYTE ( pak, 0x01 ); //buy action
ADDBYTE ( pak, invslot );
ADDWORD ( pak, BuildItemHead( otherclient->items[invslot] ) );
ADDDWORD ( pak, BuildItemData( otherclient->items[invslot] ) );
otherclient->client->SendPacket( &pak );
//update shop
RESETPACKET( pak, 0x7c6 );
ADDWORD ( pak, otherclient->clientid );
ADDBYTE ( pak, 0x05 );
ADDBYTE ( pak, 0x01 );
ADDBYTE ( pak, slot );
if(otherclient->Shop->SellingList[slot].count<=0)
{
ADDDWORD ( pak, 0x00000000 );
ADDDWORD ( pak, 0x00000000 );
}
else
{
ADDWORD ( pak, BuildItemHead( otherclient->items[invslot] ));
ADDDWORD ( pak, BuildItemData( otherclient->items[invslot] ));
}
SendToVisible( &pak, otherclient );
}
break;
default:
Log( MSG_WARNING, "Buy unknow action: %i", action );
}
return true;
}
// Sell in Shop
bool CWorldServer::pakSellShop( CPlayer* thisclient, CPacket* P )
{
//Log( MSG_INFO, "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x ", GETBYTE((*P),0), GETBYTE((*P),1), GETBYTE((*P),2), GETBYTE((*P),3), GETBYTE((*P),4), GETBYTE((*P),5), GETBYTE((*P),6), GETBYTE((*P),7), GETBYTE((*P),8), GETBYTE((*P),9), GETBYTE((*P),10), GETBYTE((*P),11), GETBYTE((*P),12), GETBYTE((*P),13), GETBYTE((*P),14), GETBYTE((*P),15), GETBYTE((*P),16), GETBYTE((*P),17), GETBYTE((*P),18), GETBYTE((*P),19), GETBYTE((*P),20), GETBYTE((*P),21), GETBYTE((*P),22), GETBYTE((*P),23), GETBYTE((*P),24) );
WORD otherclientid = GETWORD((*P),0);
BYTE action = GETBYTE((*P),2);
switch(action)
{
case 0x01:
{
CPlayer* otherclient = GetClientByID( otherclientid, thisclient->Position->Map );
if( otherclient == NULL )
return true;
unsigned int count = 0;
BYTE invslot = GETBYTE((*P),3);
BYTE slot = GETBYTE((*P),4);
if(!CheckInventorySlot( thisclient, slot))
return false;
CItem newitem = thisclient->items[invslot];
if(thisclient->items[invslot].itemtype>9 && thisclient->items[invslot].itemtype<14)
count = GETWORD((*P),7);
else
count = 1;
newitem.count = count;
if( otherclient->CharInfo->Zulies<(otherclient->Shop->BuyingList[slot].price*count) )
return true;
unsigned int newslot = otherclient->GetNewItemSlot ( newitem );
if( newslot==0xffff )
return true;
if( thisclient->items[invslot].count<count )
return true;
thisclient->CharInfo->Zulies += (otherclient->Shop->BuyingList[slot].price*count);
otherclient->CharInfo->Zulies -= (otherclient->Shop->BuyingList[slot].price*count);
if(thisclient->items[invslot].itemtype>9 &&
thisclient->items[invslot].itemtype<14)
{
if(thisclient->items[invslot].count<=count)
{
ClearItem( thisclient->items[invslot] );
if(count>=otherclient->Shop->BuyingList[slot].count)
{
ClearItem( otherclient->Shop->BuyingList[slot].item );
otherclient->Shop->BuyingList[slot].slot = 0;
otherclient->Shop->BuyingList[slot].count = 0;
otherclient->Shop->BuyingList[slot].price = 0;
}
else
{
otherclient->Shop->BuyingList[slot].count -= count;
}
}
else
{
if(otherclient->Shop->BuyingList[slot].count<=count)
{
ClearItem( otherclient->Shop->BuyingList[slot].item );
otherclient->Shop->BuyingList[slot].slot = 0;
otherclient->Shop->BuyingList[slot].count = 0;
otherclient->Shop->BuyingList[slot].price = 0;
}
else
{
otherclient->Shop->BuyingList[slot].count -= count;
}
thisclient->items[invslot].count-=count;
}
}
else
{
ClearItem( thisclient->items[invslot] )
ClearItem( otherclient->Shop->BuyingList[slot].item );
otherclient->Shop->BuyingList[slot].slot = 0;
otherclient->Shop->BuyingList[slot].count = 0;
otherclient->Shop->BuyingList[slot].price = 0;
}
if(otherclient->items[newslot].count!=0)
otherclient->items[newslot].count += newitem.count;
else
otherclient->items[newslot] = newitem;
//update inventory (seller)
BEGINPACKET( pak, 0x7c7 );
ADDQWORD ( pak, thisclient->CharInfo->Zulies );
ADDBYTE ( pak, 0x01 );
ADDBYTE ( pak, invslot );
ADDWORD ( pak, BuildItemHead( thisclient->items[invslot] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[invslot] ) );
thisclient->client->SendPacket( &pak );
//update inventory (buyer)
RESETPACKET( pak, 0x7c7 );
ADDQWORD ( pak, otherclient->CharInfo->Zulies );
ADDBYTE ( pak, 0x01 );
ADDBYTE ( pak, newslot );
ADDWORD ( pak, BuildItemHead( otherclient->items[newslot] ) );
ADDDWORD ( pak, BuildItemData( otherclient->items[newslot] ) );
otherclient->client->SendPacket( &pak );
//update shop
CItem thisitem = otherclient->Shop->BuyingList[slot].item;
RESETPACKET( pak, 0x7c6 );
ADDWORD ( pak, otherclient->clientid );
ADDBYTE ( pak, 0x07 );
ADDBYTE ( pak, 0x01 );
ADDBYTE ( pak, slot );
ADDWORD ( pak, BuildItemHead( thisitem ) );
ADDDWORD ( pak, BuildItemData( thisitem ) );
SendToVisible( &pak, otherclient );
}
break;
default:
Log( MSG_WARNING, "Sell unknow action: %i", action );
}
return true;
}
// Close Shop
bool CWorldServer::pakCloseShop( CPlayer* thisclient, CPacket* P )
{
BEGINPACKET( pak, 0x7c3 );
ADDWORD ( pak, thisclient->clientid );
ADDBYTE ( pak, 0x00 );
SendToVisible( &pak, thisclient );
thisclient->Shop->open = false;
for(unsigned int j=0;j<30;j++)
{
thisclient->Shop->SellingList[j].slot = 0;
thisclient->Shop->SellingList[j].count = 0;
thisclient->Shop->SellingList[j].price = 0;
thisclient->Shop->BuyingList[j].slot = 0;
thisclient->Shop->BuyingList[j].count = 0;
thisclient->Shop->BuyingList[j].price = 0;
ClearItem( thisclient->Shop->BuyingList[j].item );
}
return true;
}
// Modified item (put gem, refine, Drill )
bool CWorldServer::pakModifiedItem( CPlayer* thisclient, CPacket* P )
{
printf("[DEBUG]: ");
for (int i = 0;i<(P->Size-6);i++)
{
printf("%i ",GETBYTE((*P),i));
}
printf("\n");
if(thisclient->Shop->open==true)
return true;
BYTE action = GETBYTE((*P),0);
switch(action)
{
case 0x01://Gemming
{
BYTE destslot = GETBYTE((*P),1);
BYTE srcslot = GETBYTE((*P),2);
if(!CheckInventorySlot( thisclient, destslot))
return false;
if(!CheckInventorySlot( thisclient, srcslot))
return false;
if( thisclient->items[srcslot].count<=0 )
{
BEGINPACKET( pak, 0x7bc );
ADDBYTE ( pak, 0x12 ); // dont have requerid material
ADDBYTE ( pak, 0x00 );
thisclient->client->SendPacket( &pak );
return true;
}
if( thisclient->items[destslot].gem!=0 )
{
BEGINPACKET( pak, 0x7bc );
ADDBYTE ( pak, 0x02 ); //no socket available
ADDBYTE ( pak, 0x00 );
thisclient->client->SendPacket( &pak );
return true;
}
thisclient->items[destslot].gem = thisclient->items[srcslot].itemnum;
thisclient->items[destslot].stats = thisclient->items[srcslot].itemnum;
thisclient->items[srcslot].count--;
if(thisclient->items[srcslot].count<1)
ClearItem( thisclient->items[srcslot] );
BEGINPACKET( pak, 0x7bc );
ADDBYTE ( pak, 0x01 );//gemming success
ADDBYTE ( pak, 0x02 );
ADDBYTE ( pak, destslot );
ADDWORD ( pak, BuildItemHead( thisclient->items[destslot] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[destslot] ) );
ADDBYTE ( pak, srcslot );
ADDWORD ( pak, BuildItemHead( thisclient->items[srcslot] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[srcslot] ) );
thisclient->client->SendPacket( &pak );
thisclient->SetStats( );
thisclient->saveinventory();
}
break; //case 0x02 ( Surprise gift box )
case 0x02: //itemdivide by user
case 0x03: //itemdivide by npc
{
BYTE slot = GETBYTE((*P),3);
if(!CheckInventorySlot( thisclient, slot))
{
SendPM(thisclient, "Sorry! Checkinventory returned false for slot %i", slot);
return true;
}
BEGINPACKET( pak, 0x7bc )
ADDBYTE ( pak, 0x07 );//successful
ADDBYTE ( pak, 0x01 );
CItem splititem;
char updateteller = 0;
UINT material_lookup_number = STB_ITEM[(thisclient->items[slot].itemtype)-1].rows[thisclient->items[slot].itemnum][14];
UINT CraftLevel = STB_ITEM[(thisclient->items[slot].itemtype)-1].rows[thisclient->items[slot].itemnum][13];
SendPM(thisclient, "Material lookup number = %i Craft Level = %i", material_lookup_number,CraftLevel);
//first item
int matType = ProductList.Index[material_lookup_number]->matType;
int item1 = ProductList.Index[material_lookup_number]->itemid[0];
int itemtype1 = ProductList.Index[material_lookup_number]->itemtype[0];
int itemcount1 = ProductList.Index[material_lookup_number]->amount[0];
int itemcount2 = ProductList.Index[material_lookup_number]->amount[1];
int itemcount3 = ProductList.Index[material_lookup_number]->amount[2];
int itemcount4 = ProductList.Index[material_lookup_number]->amount[3];
unsigned slot1 = 0;
unsigned slot2 = 0;
unsigned slot3 = 0;
unsigned slot4 = 0;
if(matType != 0)
{
// we have to find one of the correct item types rather than just a specific item. Seems to be related to craft skill level
SendPM(thisclient, "item matType = %i", matType);
splititem.itemtype = 12; // always seems to be a natural item here
// Search the natural list and return the nth item in the list where n is the craft level of the item
splititem.itemnum = GetMatIDfromRecipe (CraftLevel, matType);
if(splititem.itemnum == 0)
{
SendPM(thisclient, "Item number returned as zero");
return true;
}
SendPM(thisclient, "Item number = %i type = %i", splititem.itemnum, splititem.itemtype);
}
else
{
splititem.itemtype = itemtype1;
splititem.itemnum = item1;
//need to adjust the count according to some rules
}
splititem.count = itemcount1;
SendPM(thisclient, "Item count = %i", splititem.count);
splititem.appraised = false;
splititem.durability = 0;
splititem.gem = 0;
splititem.lifespan = 0;
splititem.refine = 0;
splititem.socketed = 0;
splititem.stats = 0;
slot1 = thisclient->GetNewItemSlot( splititem );
if (slot1 != 0xffff)
{
splititem.count += (thisclient->items[slot1].count);
thisclient->items[slot1] = splititem;
ADDBYTE ( pak, slot1);
ADDWORD ( pak, BuildItemHead( thisclient->items[slot1] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[slot1] ) );
updateteller += 1;
}
else
{
thisclient->items[slot1].count -= itemcount1;
if(thisclient->items[slot1].count < 1)
ClearItem( thisclient->items[slot1] );
SendPM(thisclient, "Not enough free slots");
return true;
}
//second item
SendPM(thisclient, "Second item now");
splititem.itemnum = ProductList.Index[material_lookup_number]->itemid[1];
splititem.itemtype = ProductList.Index[material_lookup_number]->itemtype[1];
splititem.count = ProductList.Index[material_lookup_number]->amount[1];
splititem.appraised = false;
splititem.durability = 0;
splititem.gem = 0;
splititem.lifespan = 0;
splititem.refine = 0;
splititem.socketed = 0;
splititem.stats = 0;
SendPM(thisclient, "Item number = %i type = %i", splititem.itemnum, splititem.itemtype);
slot2 = thisclient->GetNewItemSlot( splititem );
if (slot2 != 0xffff)
{
splititem.count +=(thisclient->items[slot2].count);
thisclient->items[slot2] = splititem;
ADDBYTE ( pak, slot2);
ADDWORD ( pak, BuildItemHead( thisclient->items[slot2] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[slot2] ) );
updateteller += 1;
}
else
{
thisclient->items[slot1].count -= itemcount1;
if(thisclient->items[slot1].count < 1)
ClearItem( thisclient->items[slot1] );
thisclient->items[slot2].count -= itemcount2;
if(thisclient->items[slot2].count < 1)
ClearItem( thisclient->items[slot2] );
SendPM(thisclient, "Not enough free slots");
return true;
}
//third item (if it exists)
if(ProductList.Index[material_lookup_number]->amount[2] !=0 )
{
SendPM(thisclient, "Third item now");
splititem.itemnum = ProductList.Index[material_lookup_number]->itemid[2];
splititem.itemtype = ProductList.Index[material_lookup_number]->itemtype[2];
splititem.count = ProductList.Index[material_lookup_number]->amount[2];
splititem.appraised = false;
splititem.durability = 0;
splititem.gem = 0;
splititem.lifespan = 0;
splititem.refine = 0;
splititem.socketed = 0;
splititem.stats = 0;
SendPM(thisclient, "Item number = %i type = %i", splititem.itemnum, splititem.itemtype);
slot3 = thisclient->GetNewItemSlot( splititem );
if (slot3 != 0xffff)
{
splititem.count +=(thisclient->items[slot3].count);
thisclient->items[slot3] = splititem;
ADDBYTE ( pak, slot3);
ADDWORD ( pak, BuildItemHead( thisclient->items[slot3] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[slot3] ) );
updateteller += 1;
}
else
{
thisclient->items[slot1].count -= itemcount1;
if(thisclient->items[slot1].count < 1)
ClearItem( thisclient->items[slot1] );
thisclient->items[slot2].count -= itemcount2;
if(thisclient->items[slot2].count < 1)
ClearItem( thisclient->items[slot2] );
thisclient->items[slot3].count -= itemcount3;
if(thisclient->items[slot3].count < 1)
ClearItem( thisclient->items[slot3] );
SendPM(thisclient, "Not enough free slots");
return true;
}
}
//fourth item
if(ProductList.Index[material_lookup_number]->amount[3] !=0 )
{
splititem.itemnum = ProductList.Index[material_lookup_number]->itemid[3];
splititem.itemtype = ProductList.Index[material_lookup_number]->itemtype[3];
splititem.count = ProductList.Index[material_lookup_number]->amount[3];
splititem.appraised = false;
splititem.durability = 0;
splititem.gem = 0;
splititem.lifespan = 0;
splititem.refine = 0;
splititem.socketed = 0;
splititem.stats = 0;
slot4 = thisclient->GetNewItemSlot( splititem );
if (slot4 !=0xffff)
{
splititem.count +=(thisclient->items[slot4].count);
thisclient->items[slot4] = splititem;
ADDBYTE ( pak, slot4);
ADDWORD ( pak, BuildItemHead( thisclient->items[slot4] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[slot4] ) );
updateteller += 1;
}
else
{
thisclient->items[slot1].count -= itemcount1;
if(thisclient->items[slot1].count < 1)
ClearItem( thisclient->items[slot1] );
thisclient->items[slot2].count -= itemcount2;
if(thisclient->items[slot2].count < 1)
ClearItem( thisclient->items[slot2] );
thisclient->items[slot3].count -= itemcount3;
if(thisclient->items[slot3].count < 1)
ClearItem( thisclient->items[slot3] );
thisclient->items[slot4].count -= itemcount4;
if(thisclient->items[slot4].count < 1)
ClearItem( thisclient->items[slot4] );
SendPM(thisclient, "Not enough free slots");
return true;
}
}
/*
for(unsigned int i=0;i<STB_ITEM[11].rowcount;i++)
{
if (STB_ITEM[11].rows[i][4] == ProductList.Index[material_lookup_number]->item[0])
{
splititem.itemtype = 12;
splititem.itemnum = i;
splititem.count = ProductList.Index[material_lookup_number]->amount[0];
if(splititem.count > 1)
{
splititem.count/=2;
}
splititem.appraised = false;
splititem.durability = 0;
splititem.gem = 0;
splititem.lifespan = 0;
splititem.refine = 0;
splititem.socketed = 0;
splititem.stats = 0;
unsigned newslot = thisclient->GetNewItemSlot( splititem );
if (newslot !=0xffff)
{
splititem.count +=(thisclient->items[newslot].count);
thisclient->items[newslot] = splititem;
ADDBYTE ( pak,newslot);
ADDWORD ( pak, BuildItemHead( thisclient->items[newslot] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[newslot] ) );
updateteller+=1;
}
break;
}
}
for (char teller = 1; teller<4;teller++)
{
if (ProductList.Index[material_lookup_number]->amount[teller]>0)
{
splititem.count = ProductList.Index[material_lookup_number]->amount[teller];
if(splititem.count > 1)
{
splititem.count /= 2;
}
splititem.itemtype = (ProductList.Index[material_lookup_number]->item[teller])/1000;
splititem.itemnum = (ProductList.Index[material_lookup_number]->item[teller])-(1000*splititem.itemtype);
splititem.appraised = false;
splititem.durability = 0;
splititem.gem = 0;
splititem.lifespan = 0;
splititem.refine = 0;
splititem.socketed = 0;
splititem.stats = 0;
unsigned newslot = thisclient->GetNewItemSlot( splititem );
if (newslot !=0xffff)
{
splititem.count += (thisclient->items[newslot].count);
thisclient->items[newslot] = splititem;
ADDBYTE ( pak,newslot);
ADDWORD ( pak, BuildItemHead( thisclient->items[newslot] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[newslot] ) );
updateteller += 1;
}
}
}
*/
thisclient->items[slot].count -= 1;
ADDBYTE ( pak,slot);
if (thisclient->items[slot].count <=0)
{
ClearItem(thisclient->items[slot]);
ADDWORD ( pak,0);
ADDDWORD ( pak,0);
}
else
{
ADDWORD ( pak, BuildItemHead( thisclient->items[slot] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[slot] ) );
}
updateteller += 1;
SETBYTE(pak,1,updateteller);
thisclient->client->SendPacket( &pak );
thisclient->saveinventory();
}
break;
case 0x04://NPC Refine
case 0x05://Player Refine
{
BYTE item = GETBYTE((*P),3); //slot number
BYTE material1 = GETBYTE((*P),4); //slot number
int itemtype = thisclient->items[item].itemtype;
int itemnum = thisclient->items[item].itemnum;
if( thisclient->Session->codedebug )
{
SendPM(thisclient, "Item: %i Material: %i",item, material1 );
}
if(!CheckInventorySlot( thisclient, item))
return false;
if(!CheckInventorySlot( thisclient, material1))
return false;
//compare material1 with refinetype from equiplist
int refinetype = GServer->EquipList[itemtype].Index[itemnum]->refinetype;
int refineitem = GServer->ProductList.Index[refinetype]->item[0];
int refinecount = GServer->ProductList.Index[refinetype]->amount[0];
if( thisclient->Session->codedebug )
{
SendPM(thisclient, "Refineitem needed for this item: %i",refineitem );
}
//if(refineitem != material1)
// return false;
if(thisclient->items[item].count<1 || thisclient->items[material1].count < refinecount)
{
BEGINPACKET( pak, 0x7bc );
ADDBYTE ( pak, 0x12 );
ADDBYTE ( pak, 0x00 );
thisclient->client->SendPacket( &pak );
return true;
}
unsigned int nextlevel = ( thisclient->items[item].refine / 16 ) + 1;
if( nextlevel > 9 )
return true;//if a client were able to try and upgrade an lvl 9 grade item this would probebly lockup this client
thisclient->items[material1].count -= refinecount;
if ((thisclient->items[material1].count) < 1)
ClearItem( thisclient->items[material1] );
bool success = true;
srand( time(NULL));
unsigned int prefine = rand()%100;
//PY ToDo. This whole function needs to be recoded so that we know if it's a bindrune or a talisman
//right now the success chance is Bindrune chance (which is the same as talisman chance in the STB anyway for now)
int refinechance = upgrade[nextlevel].BindRune_Success;
if( GServer->EquipList[itemtype].Index[itemnum]->raretype != 0 )
refinechance += GServer->Config.Rare_Refine;
if( prefine > refinechance)
success = false;
BEGINPACKET( pak, 0x7bc )
if( success )
{
thisclient->items[item].refine = nextlevel*16;
thisclient->items[item].durability += nextlevel;
ADDBYTE ( pak, 0x10 );//successful
}
else
{
if(GServer->Config.KillOnFail || nextlevel > 5)
{
ClearItem( thisclient->items[item] );
}
else
{
thisclient->items[item].refine = (nextlevel-2)*16;
thisclient->items[item].durability -= 2;
}
ADDBYTE ( pak, 0x11 );//Fail
}
{ADDBYTE ( pak, 0x04 );}
ADDBYTE ( pak, material1 );
ADDWORD ( pak, BuildItemHead( thisclient->items[material1] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[material1] ) );
ADDBYTE ( pak, item );
ADDWORD ( pak, BuildItemHead( thisclient->items[item] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[item] ) );
ADDBYTE ( pak, 0x00 );
ADDDWORD ( pak, 0x002f0000 );
ADDDWORD ( pak, 0x00000017 );
thisclient->client->SendPacket( &pak );
thisclient->saveinventory();
}
break;
case 0x06: // Drill
{
BYTE material = GETBYTE((*P), 1);
BYTE item = GETBYTE((*P), 3);
int itemnum = 0;
if(!CheckInventorySlot( thisclient, item))
return false;
if(!CheckInventorySlot( thisclient, material))
return false;
//Log(MSG_INFO,"client has %i drills in slot %i",thisclient->items[material].count,material);
if( thisclient->items[material].count <= 0 )
{
BEGINPACKET( pak, 0x7bc );
ADDBYTE ( pak, 0x12 );
ADDBYTE ( pak, 0x00 );
thisclient->client->SendPacket( &pak );
return true;
}
else
{
//find the item number
itemnum = thisclient->items[material].itemnum;
//Log(MSG_INFO,"Item number = %i",itemnum);
}
//already drilled
if(thisclient->items[item].socketed)
{
BEGINPACKET( pak, 0x7bc );
ADDBYTE ( pak, 0x23 );
ADDBYTE ( pak, 0x00 );
thisclient->client->SendPacket( &pak );
return true;
}
//if( thisclient->items[item].socketed ) return true;//Show message
thisclient->items[material].count -= 1;
//thisclient->items[item].socketed = true;
if( thisclient->items[material].count <= 0 )
ClearItem(thisclient->items[material]);
//LMA: Adding some probability there :)
int success = RandNumber(0,100);
//Log(MSG_INFO,"Drill succes? %i / %i",success,UseList.Index[itemnum]->useeffect[1]);
if(success > UseList.Index[itemnum]->useeffect[1])
{
//fail
thisclient->items[item].socketed = false;
BEGINPACKET( pak, 0x7bc );
ADDBYTE ( pak, 0x21 );
ADDBYTE ( pak, 0x01 );
ADDBYTE ( pak, material);
ADDDWORD ( pak, BuildItemHead( thisclient->items[material] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[material] ) );
thisclient->client->SendPacket(&pak);
}
else
{
// success
thisclient->items[item].socketed = true;
BEGINPACKET( pak, 0x7bc );
ADDBYTE ( pak, 0x20 );
ADDBYTE ( pak, 0x02 );
ADDBYTE ( pak, material);
ADDWORD ( pak, BuildItemHead( thisclient->items[material] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[material] ) );
ADDBYTE ( pak, item );
ADDWORD ( pak, BuildItemHead( thisclient->items[item] ) );
ADDDWORD ( pak, BuildItemData( thisclient->items[item] ) );
thisclient->client->SendPacket(&pak);
}
//Log(MSG_INFO,"client now has %i drills in slot %i",thisclient->items[material].count,material);
}
thisclient->saveinventory();
break;
default:
Log( MSG_WARNING,"Modified Item unknown action: %i", action);
}
return true;
}
// Repair hammer
bool CWorldServer::pakRepairHammer( CPlayer* thisclient, CPacket* P )
{
Log( MSG_INFO, "Repairhammer. %02x %02x %02x %02x", GETBYTE((*P),0), GETBYTE((*P),1), GETBYTE((*P),2),GETBYTE((*P),3) );
UINT repairhammer = GETBYTE((*P),0);
UINT repairitem = GETBYTE((*P),2);
if (thisclient->items[repairhammer].count < 1)
return true;
thisclient->items[repairhammer].count -= 1;
if (thisclient->items[repairhammer].count < 1)
ClearItem( thisclient->items[repairhammer] );
thisclient->items[repairitem].durability -= 2;
thisclient->items[repairitem].lifespan=100;
BEGINPACKET ( pak, 0x7cb );
ADDBYTE ( pak, 0x02 );
ADDBYTE ( pak, repairhammer);
ADDWORD ( pak, BuildItemHead( thisclient->items[repairhammer] ));
ADDDWORD ( pak, BuildItemData( thisclient->items[repairhammer] ));
ADDBYTE ( pak, repairitem);
ADDWORD ( pak, BuildItemHead( thisclient->items[repairitem] ));
ADDDWORD ( pak, BuildItemData( thisclient->items[repairitem] ));
thisclient->client->SendPacket( &pak );
thisclient->saveinventory();
return true;
}
// Repair npc
bool CWorldServer::pakRepairItem( CPlayer* thisclient, CPacket* P )
{
BYTE action = GETBYTE((*P),0);
switch(action)
{
case 0x61: //Ronk
case 0x3d:
case 0x39:
case 0x1c:
case 0x08:
case 0x74:
case 0x89:
case 0x12: // Raffle
case 0x43: //NPC Repair Item / Town
{
BYTE slot = GETBYTE((*P),2);
if(!CheckInventorySlot( thisclient, slot)) return false;
if(thisclient->items[slot].count<1) return true;
//Log( MSG_INFO,"Item socketed?: %i", thisclient->items[slot].socketed);
thisclient->items[slot].lifespan = 100;
//Log( MSG_INFO,"Item socketed?: %i", thisclient->items[slot].socketed);
//Still TODO: find where prices of storage and repair are and add it to the code.
BEGINPACKET( pak, 0x7cd );
ADDQWORD ( pak, thisclient->CharInfo->Zulies );
ADDBYTE ( pak, 0x01 );
ADDBYTE ( pak, slot );
ADDWORD ( pak, BuildItemHead( thisclient->items[slot] ));
ADDDWORD ( pak, BuildItemData( thisclient->items[slot] ));
ADDBYTE ( pak, 0x00 );
thisclient->client->SendPacket( &pak );
thisclient->SetStats( );
thisclient->saveinventory();
}
break;
default:
Log( MSG_WARNING,"Repair Item unknown action: %i", action);
break;
}
return true;
}
// Ride request
bool CWorldServer::pakRideRequest( CPlayer* thisclient, CPacket* P )
{
if(thisclient->Shop->open)
return true;
BYTE action = GETBYTE((*P),0);
switch(action)
{
case 0x01://Ride Request
{
WORD tclientid = GETWORD((*P),1);
WORD oclientid = GETWORD((*P),3);
if( tclientid != thisclient->clientid )
return true;
CPlayer* otherclient = GetClientByID( oclientid, thisclient->Position->Map );
if(otherclient == NULL)
return true;
BEGINPACKET( pak, 0x7dd );
ADDBYTE ( pak, 0x01 );
ADDWORD ( pak, thisclient->clientid );
ADDWORD ( pak, oclientid );
ADDFLOAT ( pak, thisclient->Position->current.x*100 );
ADDFLOAT ( pak, thisclient->Position->current.y*100 );
otherclient->client->SendPacket( &pak );
}
break;
case 0x02://Accept
{
WORD oclientid = GETWORD((*P),1);
WORD tclientid = GETWORD((*P),3);
if( tclientid != thisclient->clientid )
return true;
CPlayer* otherclient = GetClientByID( oclientid, thisclient->Position->Map );
if(otherclient == NULL)
return true;
BEGINPACKET( pak, 0x796 );
ADDWORD ( pak, tclientid );
ADDFLOAT ( pak, thisclient->Position->current.x*100 );
ADDFLOAT ( pak, thisclient->Position->current.y*100 );
ADDWORD ( pak, 0x0000 );
SendToVisible( &pak, otherclient );
RESETPACKET( pak, 0x7dd );
ADDBYTE ( pak, 0x02 );
ADDWORD ( pak, oclientid );
ADDWORD ( pak, tclientid );
SendToVisible( &pak, otherclient );
thisclient->Ride->Ride = true;
thisclient->Ride->Drive = false;
thisclient->Ride->charid = otherclient->CharInfo->charid;
otherclient->Ride->Ride = true;
otherclient->Ride->Drive = true;
otherclient->Ride->charid = thisclient->CharInfo->charid;
}
break;
case 0x03://Denied
{
WORD oclientid = GETWORD((*P),1);
WORD tclientid = GETWORD((*P),3);
if( tclientid != thisclient->clientid )
return true;
CPlayer* otherclient = GetClientByID( oclientid, thisclient->Position->Map );
if(otherclient == NULL)
return true;
BEGINPACKET( pak, 0x7dd );
ADDBYTE ( pak, 0x03 );
ADDWORD ( pak, oclientid );
ADDWORD ( pak, tclientid );
otherclient->client->SendPacket( &pak );
}
break;
}
return true;
}
bool CWorldServer::pakWeight( CPlayer* thisclient, CPacket* P )
{
BYTE weight = GETBYTE((*P),0) & 0xff;
if(weight>110)
thisclient->Status->CanAttack = false;
else
thisclient->Status->CanAttack = true;
if(weight>100)
thisclient->Status->CanRun = false;
else
thisclient->Status->CanRun = true;
thisclient->Stats->Move_Speed = thisclient->GetMoveSpeed( );
BEGINPACKET( pak, 0x762 );
ADDWORD ( pak, thisclient->clientid );
ADDBYTE ( pak, weight );
thisclient->client->SendPacket( &pak );
return true;
}
// Show Monster HP or Player Regeneration
bool CWorldServer::pakShowHeal( CPlayer* thisclient, CPacket* P )
{
WORD clientid = GETWORD((*P),0);
CCharacter* character = MapList.Index[thisclient->Position->Map]->GetCharInMap( clientid );
if(character == NULL) return true;
if(character->IsMonster())
{
// SET MONSTER HEALTH
BEGINPACKET( pak, 0x79f );
ADDWORD( pak, character->clientid );
ADDWORD( pak, character->Stats->HP );
ADDWORD( pak, 0 );
thisclient->client->SendPacket( &pak );
//thisclient->Battle->contatk = false;
}
//thisclient->Battle->target = clientid;
return true;
}
// Disconnect char
bool CWorldServer::pakCharDSClient( CPlayer* thisclient, CPacket* P )
{
if(!thisclient->Session->isLoggedIn) return true;
BYTE action = GETBYTE((*P),0);
switch(action)
{
case 1:
{
unsigned int userid = GETDWORD((*P), 1 );
CPlayer* otherclient = GetClientByUserID( userid );
if(otherclient==NULL)
{
Log(MSG_WARNING, "userid '%s' not found online", userid );
return true;
}
otherclient->client->isActive = false;
}
break;
default:
break;
}
return true;
}
// Pack Printscreen
bool CWorldServer::pakPrintscreen( CPlayer* thisclient, CPacket* P )
{
BEGINPACKET( pak, 0x7eb );
ADDWORD ( pak, thisclient->Session->userid );
ADDWORD ( pak, 0x0302 );
ADDWORD ( pak, 0x2d17 );
thisclient->client->SendPacket( &pak );
return true;
}
// CharServer Connected
bool CWorldServer::pakCSReady ( CPlayer* thisclient, CPacket* P )
{
if(thisclient->Session->isLoggedIn) return false;
if(GETDWORD((*P),0) != Config.WorldPass )
{
Log( MSG_HACK, "CharServer Tried to connect WorldServer with wrong password ");
return true;
}
thisclient->Session->isLoggedIn=true;
return true;
}
// CharServer - Disconnect User
bool CWorldServer::pakCSCharSelect ( CPlayer* thisclient, CPacket* P )
{
if(!thisclient->Session->isLoggedIn) return false;
Log( MSG_INFO, "Char server requested client kill" );
DWORD userid = GETDWORD( (*P), 0 );
CPlayer* otherclient = GetClientByUserID( userid );
if(otherclient != NULL)
{
if(otherclient->client==NULL) return true;
otherclient->client->isActive = false;
}
Log( MSG_INFO, "Client killed" );
return true;
}
bool CWorldServer::pakItemMall( CPlayer* thisclient, CPacket* P )
{
return true;
}