// Send Clan information bool CCharServer::SendClanInfo (CCharClient* thisclient) { if( thisclient->clanid > 0 ) { CClans *thisclan = GetClanByID(thisclient->clanid); if(thisclan!=NULL) { BEGINPACKET( pak, 0x7e0); ADDBYTE ( pak, 0x33);//0x33 you have invited to clan ADDWORD ( pak, thisclan->id);// clan id ADDBYTE ( pak, 0x00);// ADDBYTE ( pak, 0x00); ADDWORD ( pak, thisclan->back);//Clan Background ADDWORD ( pak, thisclan->logo);//Clan logo ADDBYTE ( pak, thisclan->grade);//Clan grade ADDBYTE ( pak, thisclient->clan_rank);// Clan rank (0 = red rokie / 6 = master) ADDDWORD ( pak, thisclan->cp);//Clan Points ADDDWORD ( pak, 0x00000064); ADDDWORD ( pak, 0x00000000); //Clan found ADDDWORD ( pak, 0x00000000); ADDBYTE ( pak, 0x01); for(int i=34;i<156;i++) ADDBYTE ( pak, 0x00); ADDWORD ( pak, 0x0000); ADDBYTE ( pak, 0x00); ADDSTRING ( pak, thisclan->name);//Clan Name ADDBYTE ( pak, 0x00); ADDSTRING ( pak, thisclan->slogan);//Clan slogan ADDBYTE ( pak, 0x00); ADDSTRING ( pak, thisclan->news);//Clan news ADDBYTE ( pak, 0x00); thisclient->SendPacket(&pak); //Put the player online in clan for(UINT i=0;i<thisclan->ClanMembers.size();i++) { CClanMembers* ClanMember = thisclan->ClanMembers.at( i );; CCharClient* otherclient = GetClientByID( ClanMember->id ); if(otherclient!=NULL) ChangeClanStatus (thisclient, otherclient, thisclient->channel);//send channel here } } } return true; }
bool CMap::DeleteDrop( CDrop* drop ) { BEGINPACKET( pak, 0x794 ); ADDWORD ( pak, drop->clientid ); GServer->SendToVisible( &pak, drop ); GServer->ClearClientID( drop->clientid ); for(UINT j=0;j<DropsList.size();j++) { if(drop==DropsList.at(j)) { DropsList.erase( DropsList.begin()+j ); delete drop; return true; } } delete drop; return false; }
// Send Server encryption bool CLoginServer::pakEncryptionRequest( CLoginClient* thisclient, CPacket* P ) { BEGINPACKET( pak, 0x7ff ); ADDWORD ( pak, 0xaf02 ); ADDWORD ( pak, 0xbd46 ); ADDWORD ( pak, 0x0009 ); ADDWORD ( pak, 0x0012 ); ADDBYTE ( pak, 0x0000 ); ADDDWORD ( pak, 0xcdcdcdcd ); ADDDWORD ( pak, 0xcdcdcdcd ); ADDDWORD ( pak, 0xcdcdcdcd ); ADDDWORD ( pak, 0xcdcdcdcd ); ADDWORD ( pak, 0xcdcd ); ADDBYTE ( pak, 0xd3 ); thisclient->SendPacket( &pak ); Log(MSG_DEBUG, "Sent a 0x7ff packet to client"); return true; }
// Change player status in clan ((channel) = online/ 0xff = offline) bool CCharServer::ChangeClanStatus (CCharClient* thisclient, CCharClient* otherclient, int channel) { if (thisclient->charid !=otherclient->charid) { BEGINPACKET( pak, 0x7e0 ); ADDBYTE ( pak, 0x73 );//Change player status ADDBYTE ( pak, 0x00 ); ADDBYTE ( pak, channel );//CANAL ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, thisclient->level ); ADDWORD ( pak, thisclient->job ); ADDSTRING ( pak, thisclient->charname ); ADDBYTE ( pak, 0x00 ); otherclient->SendPacket(&pak); } return true; }
// do buff skill bool CCharacter::BuffSkill( CCharacter* Target, CSkills* skill ) { Position->destiny = Position->current; //if(Battle->castTime == 0) //{ BEGINPACKET( pak, 0x7bb ); ADDWORD ( pak, clientid ); GServer->SendToVisible( &pak, (CCharacter*)this ); // Battle->castTime = clock(); // return true; //} //else //{ // clock_t etime = clock() - Battle->castTime; // if(etime < SKILL_DELAY) // return true; //} //Battle->castTime = 0; //Log(MSG_DEBUG,"applied buff skill %i",skill->id); UseBuffSkill( Target, skill ); Stats->MP -= (skill->mp - (skill->mp * Stats->MPReduction / 100)); if(Stats->MP < 0) Stats->MP = 0; GServer->DoSkillScript( this, skill ); //summons a monster. Why do we do this for all skills? if(!IsMonster()) { ClearBattle( Battle ); // clear battle for players when they use buff skills //Battle->bufftarget = 0; //Battle->skilltarget = 0; //Battle->skillid = 0; //Battle->atktype = NORMAL_ATTACK; } else //Monsters need to be reset to normal attack and clear skill attacks. { //Battle->atktarget = Battle->target; //Battle->bufftarget = 0; //Battle->skilltarget = 0; //Battle->skillid = 0; //Battle->atktype = NORMAL_ATTACK; //StartAction(Target, NORMAL_ATTACK); } Battle->lastAtkTime = clock( ); Battle->iscasting = 1; return true; }
// Do player identification bool CCharServer::pakDoIdentify( CCharClient* thisclient, CPacket* P ) { if (thisclient->isLoggedIn) return false; MYSQL_RES *result; MYSQL_ROW row; thisclient->userid = GETDWORD((*P), 0x00); memcpy( thisclient->password, &P->Buffer[4], 32 ); result = DB->QStore("SELECT username,lastsvr,accesslevel,platinum FROM accounts WHERE id=%i AND password='******'", thisclient->userid, thisclient->password); if(result==NULL) return false; if (mysql_num_rows( result ) != 1) { Log( MSG_HACK, "Someone tried to connect to char server with an invalid account" ); DB->QFree( ); return false; } else { row = mysql_fetch_row(result); strncpy(thisclient->username, row[0],16); thisclient->channel = atoi(row[1]); thisclient->accesslevel = atoi(row[2]); thisclient->platinum = atoi(row[3]); DB->QFree( ); } Log( MSG_INFO,"User '%s'(#%i) logged in", thisclient->username, thisclient->userid ); BEGINPACKET( pak, 0x070c ); ADDBYTE ( pak, 0 ); ADDDWORD ( pak, 0x87654321); ADDDWORD ( pak, 0x00000000 ); thisclient->SendPacket( &pak ); result = DB->QStore( "SELECT online FROM accounts WHERE username='******'", thisclient->username ); if(result==NULL) return false; row = mysql_fetch_row(result); bool online = atoi(row[0]); DB->QFree( ); if(online) return false; if(!DB->QExecute( "UPDATE accounts SET online=1 WHERE username='******'", thisclient->username )) return false; thisclient->isLoggedIn = true; return true; }
// convert a npc to other [not working] CMonster* CMap::ConverToMonster( CNPC* npc, UINT newmontype ) { CMonster* monster = AddMonster( newmontype, npc->pos, 0, NULL, NULL, 0, true ); if(monster==NULL) // invalid montype return NULL; GServer->ClearClientID( monster->clientid ); monster->clientid = npc->clientid; for(UINT i=0;i<NPCList.size();i++) { if(NPCList.at(i)==npc) NPCList.erase( NPCList.begin()+i ); } delete npc; BEGINPACKET( pak, 0x774 ); ADDWORD ( pak, npc->clientid ); ADDWORD ( pak, newmontype ); GServer->SendToVisible( &pak, monster ); return monster; }
// Move a mob (random place) void CMonster::Move( ) { Position->destiny = GServer->RandInCircle( Position->source, 10 ); // Position->lastMoveTime = clock(); ClearBattle( Battle ); BEGINPACKET( pak, 0x797 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, 0x0000 );//??? ADDWORD ( pak, Stats->Move_Speed ); //speed ADDFLOAT ( pak, Position->destiny.x*100 ); ADDFLOAT ( pak, Position->destiny.y*100 ); ADDWORD ( pak, 0xcdcd ); //ADDBYTE ( pak, 0x01 ); ADDBYTE ( pak, thisnpc->stance ); //AIP GServer->SendToVisible(&pak, this); if(Position->Map==8) Log(MSG_INFO,"Move (%.2f;%.2f) to (%.2f;%.2f)",Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y); }
// Move a mob (specified point) void CMonster::MoveTo( fPoint nPos, bool randcircle ) { if(randcircle) Position->destiny = GServer->RandInCircle( nPos, 5 ); else Position->destiny = nPos; // Position->lastMoveTime = clock(); BEGINPACKET( pak, 0x797 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, 0x0000 ); // ??? ADDWORD ( pak, Stats->Move_Speed ); ADDFLOAT ( pak, Position->destiny.x*100 ); ADDFLOAT ( pak, Position->destiny.y*100 ); ADDWORD ( pak, 0xcdcd ); //ADDBYTE ( pak, 0x01 ); ADDBYTE ( pak, thisnpc->stance); //AIP GServer->SendToVisible(&pak, this ); if(Position->Map==8) Log(MSG_INFO,"MoveTo (%.2f;%.2f) to (%.2f;%.2f)",Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y); }
bool CMap::DeleteNPC( CNPC* npc ) { BEGINPACKET( pak, 0x794 ); ADDWORD ( pak, npc->clientid ); GServer->SendToMap( &pak, npc->posMap ); GServer->ClearClientID( npc->clientid ); for(UINT j=0;j<NPCList.size();j++) { if(npc==NPCList.at(j)) { NPCList.erase( NPCList.begin()+j ); delete npc; return true; } } delete npc; return false; return true; }
bool CMap::RemovePlayer( CPlayer* player, bool clearobject ) { GServer->ClearClientID( player->clientid ); if(clearobject) { BEGINPACKET( pak, 0x794 ); ADDWORD ( pak, player->clientid ); GServer->SendToVisible( &pak, player, false ); } for(UINT i=0;i<PlayerList.size();i++) { if(PlayerList.at(i)==player) { PlayerList.erase( PlayerList.begin()+i ); return true; } } Log(MSG_WARNING, "Player not founded %s", player->CharInfo->charname ); return false; }
// upload clanmark bool CCharServer::pakUploadCM ( CCharClient* thisclient, CPacket* P ) { CClans* thisclan = GetClanByID( thisclient->clanid ); if(thisclan==NULL) return true; FILE* fh = fopen( "clanmark/clanmark.cnt", "r+b" ); if(fh==NULL) { Log( MSG_WARNING, "Error opening clanmark counter file" ); return true; } rewind(fh); unsigned int cmid = 0;// this will be our clanmark id unsigned int tcmid = 0;// this will be to update the id fread( &cmid, 1, 4, fh ); tcmid = cmid+1; rewind(fh); fwrite( &tcmid, 1, 4, fh ); fclose(fh); thisclan->logo = GETWORD((*P), 0 );//cmid; thisclan->back = 0; char filename[30]; sprintf( filename, "clanmark/%u.cm", thisclan->logo ); fh = fopen( filename, "w+b" ); if(fh==NULL) { Log( MSG_WARNING, "Error creating clanmark file" ); return true; } rewind(fh); for(unsigned int i=0;i<P->Size-6;i++) fwrite( &P->Buffer[i], 1, 1, fh ); fclose(fh); DB->QExecute("UPDATE list_clan SET logo=%i,back=0 WHERE id=%i",thisclan->logo, thisclient->clanid ); BEGINPACKET( pak, 0x7e1 );//update clan info in world ADDBYTE ( pak, 0xff ); ADDWORD ( pak, thisclient->clanid ); ADDDWORD ( pak, cmid ); for(int i=0;i<ChannelList.size();i++) send( ChannelList.at(i)->sock, (char*)&pak, pak.Size, 0 ); return true; }
// Send server IP bool CLoginServer::pakGetIP( CLoginClient* thisclient, CPacket* P ) { if (!thisclient->isLoggedIn) return false; ; MYSQL_ROW row; DWORD servernum = GETDWORD( (*P), 0 ); BYTE channelnum = GETBYTE( (*P), 4 ); BEGINPACKET( pak, 0x70a ); if(!DB->QExecute( "UPDATE accounts SET lastsvr=%i,lastip='%s',lasttime=UNIX_TIMESTAMP( NOW() ) WHERE id=%i", channelnum, inet_ntoa( thisclient->clientinfo.sin_addr ), thisclient->userid)) return false; MYSQL_RES *result = DB->QStore( "SELECT host,port,lanip,lansubmask FROM channels WHERE id=%i and type=1", servernum ); if(result==NULL) return false; if(mysql_num_rows(result)!=1) { Log(MSG_WARNING, "Player selected a invalid channel or channel offline" ); DB->QFree( ); return true; } row = mysql_fetch_row(result); ADDBYTE( pak, 0 ); ADDDWORD( pak, thisclient->userid ); ADDDWORD( pak, 0x87654321 ); if(strcmp(thisclient->ClientSubNet, row[3])==0)//Lan { ADDSTRING( pak, row[2] ); } else if(strcmp( thisclient->ClientSubNet ,"127.0.0")==0) { //localhost ADDSTRING( pak, "127.0.0.1" ); } else { // Other ADDSTRING( pak, row[0] ); } ADDBYTE( pak, 0 ); ADDWORD( pak, atoi(row[1]) ); DB->QFree( ); thisclient->SendPacket ( &pak ); return true; }
void CPlayer::UpdateInventory( unsigned int slot1, unsigned int slot2 ) { if(slot1 == 0xffff && slot2 == 0xffff) return; //neither slot is valid BEGINPACKET( pak, 0x718 ); if(slot1 != 0xffff && slot2 != 0xffff) {ADDBYTE( pak, 2 );} //both slots are valid else {ADDBYTE( pak, 1 );} //one of the slots is valid if(slot1 != 0xffff) { ADDBYTE ( pak, slot1); ADDWORD ( pak, GServer->BuildItemHead( items[slot1] ) ); ADDDWORD ( pak, GServer->BuildItemData( items[slot1] ) ); } if(slot2 != 0xffff) { ADDBYTE ( pak, slot2 ); ADDWORD ( pak, GServer->BuildItemHead( items[slot2] ) ); ADDDWORD ( pak, GServer->BuildItemData( items[slot2] ) ); } client->SendPacket( &pak ); }
// convert a monster to other CMonster* CMap::ConverToMonster( CMonster* monster, UINT newmontype, bool heal ) { CNPCData* thisnpc = GServer->GetNPCDataByID( newmontype ); if(thisnpc==NULL)// invalid type return NULL; monster->montype = newmontype; monster->thisnpc = thisnpc; monster->SetStats( ); if(heal) monster->Stats->HP = monster->GetMaxHP(); if(monster->owner==0) { monster->MonsterDrop->mobdrop = GServer->GetDropData( monster->thisnpc->dropid ); monster->MonsterDrop->mapdrop = GServer->GetDropData( id ); } BEGINPACKET( pak, 0x774 ); ADDWORD ( pak, monster->clientid ); ADDWORD ( pak, newmontype ); GServer->SendToVisible( &pak, monster ); monster->OnSpawn( false ); return monster; }
// NPC Announce to the server bool CWorldServer::NPCAnnounce( char* msg, char* npc, int mapid) { //LMA: We only announce in the NPC's map //Log(MSG_INFO,"%s announces: %s",npc,msg); BEGINPACKET( pak, 0x702 ); ADDSTRING( pak, npc ); ADDSTRING( pak, "> " ); ADDSTRING( pak, msg); ADDBYTE( pak, 0x00); if(mapid!=0) { SendToMap ( &pak, mapid ); } else { SendToAll( &pak ); } return true; }
// HP/MP Regeneration Function bool CPlayer::Regeneration() { if (Stats->MaxHP == Stats->HP && Stats->MaxMP == Stats->MP) { lastRegenTime = 0; return true; } bool is_first_regen = false; if (lastRegenTime == 0) { is_first_regen = true; } clock_t etime = clock() - lastRegenTime; if( etime >= 8 * CLOCKS_PER_SEC && Stats->HP > 0 ) { //Log(MSG_INFO,"Regeneration function. Character %i HP on entry %i", clientid, Stats->HP); unsigned int hpamount = GetHPRegenAmount( ); unsigned int mpamount = GetMPRegenAmount( ); Stats->HP += hpamount; Stats->MP += mpamount; if( Stats->HP > Stats->MaxHP) Stats->HP = Stats->MaxHP; if( Stats->MP > Stats->MaxMP ) Stats->MP = Stats->MaxMP; BEGINPACKET( pak, 0x7ec ); ADDWORD( pak, Stats->HP); ADDWORD( pak, Stats->MP ); client->SendPacket( &pak ); if (Stats->MaxHP == Stats->HP && Stats->MaxMP == Stats->MP) lastRegenTime = 0; else lastRegenTime = clock(); //Log(MSG_INFO,"Regeneration function. Character %i HP on exit %i clock time %i", clientid, Stats->HP, lastRegenTime); } return true; }
void CPlayer::UpdateInventory( unsigned int slot1, unsigned int slot2 ) { if(slot1==0xffff && slot2==0xffff) return; BEGINPACKET( pak, 0x718 ); if(slot2!=0xffff && slot2!=0xffff) {ADDBYTE( pak, 2 );} else {ADDBYTE( pak, 1 );} if(slot1!=0xffff) { ADDBYTE ( pak, slot1); ADDWORD ( pak, GServer->BuildItemHead( items[slot1] ) ); ADDDWORD ( pak, GServer->BuildItemData( items[slot1] ) ); } if(slot2!=0xffff) { ADDBYTE ( pak, slot2 ); ADDWORD ( pak, GServer->BuildItemHead( items[slot2] ) ); ADDDWORD ( pak, GServer->BuildItemData( items[slot2] ) ); } client->SendPacket( &pak ); }
// Delete a monster bool CMap::DeleteMonster( CMonster* monster, bool clearobject, UINT i ) { if(monster==NULL) return false; GServer->ClearClientID( monster->clientid ); if(monster->Position->respawn!=0) { CSpawnArea* thisspawn = GServer->GetSpawnArea( monster->Position->respawn, monster->Position->Map ); if(thisspawn!=NULL) thisspawn->amon--; } if(clearobject) { BEGINPACKET( pak, 0x799 ); ADDWORD ( pak, monster->clientid ); ADDWORD ( pak, monster->clientid ); ADDDWORD ( pak, monster->Stats->HP ); ADDDWORD ( pak, 16 ); GServer->SendToVisible( &pak, monster ); } if(i!=0) { MonsterList.erase( MonsterList.begin()+i ); delete monster; return true; } for(UINT i=0; i<MonsterList.size(); i++) { CMonster* othermon = MonsterList.at(i); if(othermon==monster) { MonsterList.erase( MonsterList.begin()+i ); delete monster; return true; } } delete monster; return false; }
// Send clan members bool CCharServer::pakClanMembers ( CCharClient* thisclient ) { CClans* thisclan = (CClans*) GetClanByID( thisclient->clanid ); if(thisclan!=NULL) { BEGINPACKET( pak, 0x7e0 ); ADDBYTE ( pak, 0x72 );//Send clan members for(UINT i=0;i<thisclan->ClanMembers.size( );i++) { CClanMembers* thismember = thisclan->ClanMembers.at( i ); if(thismember==NULL) continue; CCharClient* otherclient = (CCharClient*) GetClientByID (thismember->id); if(otherclient!=NULL) { ADDBYTE ( pak, thismember->clan_rank ); //clan rank ADDBYTE ( pak, otherclient->channel ); //channel (0x01 = channel 1) ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, otherclient->level );// Level ADDWORD ( pak, otherclient->job );// Job } else { ADDBYTE ( pak, thismember->clan_rank); //clan rank ADDBYTE ( pak, 0xff ); //channel (0xff = offline) ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, 0x0000 );// Level ADDWORD ( pak, 0x0000 );// Job } ADDSTRING ( pak, thismember->name ); ADDBYTE ( pak, 0x00 ); } thisclient->SendPacketCpy( &pak ); } return true; }
// do skill attack bool CCharacter::SkillAttack( CCharacter* Enemy, CSkills* skill ) { Position->destiny = Position->current; //if(Battle->castTime == 0) //{ BEGINPACKET( pak, 0x7bb ); ADDWORD ( pak, clientid ); GServer->SendToVisible( &pak, this ); // Battle->castTime = clock(); // return true; //} //else //{ // clock_t etime = clock() - Battle->castTime; // if(etime < SKILL_DELAY) // return true; //} //Battle->castTime = 0; UseAtkSkill( Enemy, skill ); Stats->MP -= (skill->mp - (skill->mp * Stats->MPReduction / 100)); if(Stats->MP < 0) Stats->MP = 0; //Battle->atktype = NORMAL_ATTACK; //Battle->skilltarget = 0; //Battle->atktarget = Battle->target; //Battle->skillid = 0; GServer->DoSkillScript( this, skill ); Battle->lastAtkTime = clock( ); if(Enemy->IsDead()) ClearBattle(Battle); Battle->iscasting = 1; //Log(MSG_DEBUG,"Cast a skill. Iscasting set to true"); return true; }
// convert a monster to other CMonster* CMap::ConverToMonster( CMonster* monster, UINT newmontype, bool heal ) { CNPCData* thisnpc = GServer->GetNPCDataByID( newmontype ); if(thisnpc == NULL)// invalid type return NULL; int spawnid = monster->Status->spawnid; monster->montype = newmontype; monster->thisnpc = thisnpc; monster->SetStats( ); if(heal) monster->Stats->HP = monster->Stats->MaxHP; if(monster->owner == 0) { monster->MonsterDrop->mobdrop = GServer->GetDropData( monster->thisnpc->dropid ); monster->MonsterDrop->mapdrop = GServer->GetDropData( id ); } BEGINPACKET( pak, 0x774 ); ADDWORD ( pak, monster->clientid ); ADDWORD ( pak, newmontype ); GServer->SendToVisible( &pak, monster ); monster->OnSpawn( false ); monster->Status->spawnid = spawnid; //make sure the monster retains the original spawnid. Don't see why it should be lost though. return monster; }
// Return to char select bool CCharServer::pakWSCharSelect ( CCharClient* thisclient, CPacket* P ) { if(!thisclient->isLoggedIn) return false; Log( MSG_INFO, "World server requested char select" ); DWORD userid = GETDWORD( (*P), 0 ); CCharClient* otherclient = GetClientByUserID( userid ); if(otherclient==NULL) { Log(MSG_WARNING, "Invalid userid: %i", userid ); return true; } BEGINPACKET( pak, 0x71c ); ADDBYTE ( pak, 0x00 ); otherclient->SendPacket( &pak ); Log( MSG_INFO, "Client returning to char select" ); RESETPACKET( pak, 0x505 ); ADDDWORD( pak, thisclient->userid ); cryptPacket( (char*)&pak, NULL ); CChanels* thischannel = GetChannelByID( thisclient->channel ); if(thischannel!=NULL) send( thischannel->sock, (char*)&pak, pak.Size, 0 ); return true; }
// This function is called just before the server starts bool CWorldServer::OnServerReady( ) { ServerOnline = true; GServer = this; clock_t timer = clock(); LastUpdateTime = clock(); ATTK_SPEED_MODIF = 120; HIT_DELAY_MODIF = 0; MOVE_SPEED_MODIF = 100000; //LMA: We init ObjVar, just in case. for (int k=0;k<MAX_NPC;k++) { for (int j=0;j<20;j++) { ObjVar[k][j]=0; } } //Load our Server Info LoadConfig( ); //LoadLTB( ); LoadSTBData( ); LoadIfoObjects(); //LMA: init default values. InitDefaultValues(); LoadZoneData( ); LoadGrids( ); //resetting grids... LoadConsItem( ); LoadSellData( ); LoadProductItem( ); LoadPatItem( ); LoadNaturalItem( ); LoadJemItem( ); LoadEquip( ); LoadItemStats( ); // PY new Stat Lookup table LoadStatLookup( ); // PY end //LoadBreakList( ); // geo edit for disassemble // 22 oct 07 LoadBreakChestBlueList(); //LMA: loading chests, breaks from STB... LoadSkillData( ); //LMA: Forcing Union Wars. UWForceFrom=0; //deactivated. UWNbPlayers=0; //deactivated //In t + 5 minutes (deactivated, use gm command instead). //pakGMForceUW(NULL,5); //LMA: for debug (load old skill system and compares to new one). /* LoadSkillDataOld( ); LMACheckSkills(); LMACheckStuff(); */ //End debug. //Load our Server Info LoadQuestSTB(); //hidden // LoadDropsData( ); // new drops routine load LoadPYDropsData( ); LoadSkillBookDropsData( ); // end of new drops data //LoadChestData( ); //LMA: loaded now by STB in LoadBreakChestBlueList. // PY custom events start LoadCustomTeleGate( ); LoadCustomEvents( ); // PY custom events end LoadNPCData( ); LoadQuestItemData( ); LoadTeleGateData( ); LoadRespawnData( ); LoadMobGroups( ); LoadMobGroupsSpecial( ); //LMA: Special spawns (Halloween for example). LoadNPCs( ); LoadNPCsSpecial( ); //Special NPC load LoadMonsters( ); LoadUpgrade( ); LoadLTB(); //LMA: Loading LTB for AIP. LoadQuestData( ); LoadAipData(); //LMA: loading AIP. CleanConnectedList( ); Log(MSG_INFO, "Database Loaded " ); pthread_create( &WorldThread[WORLD_THREAD], &at, WorldProcess, NULL); pthread_create( &WorldThread[VISUALITY_THREAD], &at, VisibilityProcess, NULL); pthread_create( &MapThread[0], &at, MapProcess, NULL); Log (MSG_INFO, "osRose Revision %s", Config.osRoseVer ); Log( MSG_INFO, "Process Loaded. WorldDelay %i | MapDelay %i | VisualDelay %i",Config.WorldDelay,Config.MapDelay,Config.VisualDelay); DB->QExecute( "DELETE FROM channels WHERE id=%u and type=%i", Config.ServerID, Config.ServerType ); if(!DB->QExecute("INSERT INTO channels (id,type,name,host,port,lanip,lansubmask,connected,maxconnections,owner) VALUES (%i,%i,'%s','%s',%u,'%s','%s',0,%i,%i)", Config.ServerID, Config.ServerType, Config.ServerName, Config.WorldIP, Config.WorldPort, Config.LanIP, Config.LanSubnet, Config.MaxConnections, Config.ParentID)) { Log(MSG_WARNING, "Error accessing to database, the other server will not connect to WorldServer" ); } MYSQL_ROW row; bool pflag = false; //Get IP and Port from Charserver MYSQL_RES *result = DB->QStore( "SELECT host,port,lanip FROM channels WHERE id=%u and type=1", Config.ParentID ); if(result==NULL) return false; if (mysql_num_rows( result ) == 1) { row = mysql_fetch_row( result ); switch(Config.Connection) { case 0://wanip Config.CharIP = row[0]; break; case 1://lanip Config.CharIP = row[2]; break; default://localhost Config.CharIP = "127.0.0.1"; break; } Config.CharPort = atoi(row[1]); pflag = true; } DB->QFree( ); if(pflag) { Log( MSG_INFO, "Initialized Charserver connection" ); // Connect To LoginServer csock = socket( AF_INET, SOCK_STREAM, 0 ); if (csock == INVALID_SOCKET) { Log( MSG_WARNING, "Could not access login server" ); } struct sockaddr_in ain; ain.sin_family = AF_INET; ain.sin_addr.s_addr = inet_addr( Config.CharIP ); ain.sin_port = htons( Config.CharPort ); if ( connect( csock, (SOCKADDR*) &ain, sizeof(ain) ) == SOCKET_ERROR ) Log( MSG_WARNING, "Could not access charserver" ); BEGINPACKET( pak, 0x500 ); ADDDWORD ( pak, Config.CharPass ); ADDDWORD ( pak, Config.ServerID ); ADDWORD ( pak, Config.WorldPort ); cryptPacket( (char*)&pak, NULL ); send( csock, (char*)&pak, pak.Size, 0 ); } float loadtime = (float)( clock() - timer ) / CLOCKS_PER_SEC; Log( MSG_INFO, "Server took %.4f seconds to load", loadtime ); return true; }
// This cleans up our clients mess :P void CWorldServer::OnClientDisconnect( CClientSocket* thisclient ) { if(thisclient->player==NULL) return; CPlayer* player = (CPlayer*)thisclient->player; if(!player->Session->isLoggedIn) return; if(!player->Saved) { player->savedata(); player->Session->isLoggedIn = false; //send packet to change messenger status (offline) BEGINPACKET( pak, 0x7e1 ); ADDBYTE ( pak, 0xfa ); ADDWORD ( pak, player->CharInfo->charid ); ADDBYTE ( pak, 0x00 ); cryptPacket( (char*)&pak, NULL ); send( csock, (char*)&pak, pak.Size, 0 ); } if ( player->Fairy ) { FairyList.at(player->FairyListIndex)->assigned = false; FairyList.at(player->FairyListIndex)->LastTime = clock(); FairyList.at(player->FairyListIndex)->ListIndex = 0; FairyList.at(player->FairyListIndex)->WaitTime = Config.FairyWait * (rand()% GetFairyRange(1)+ GetFairyRange(0)); player->Fairy = false; player->FairyListIndex = 0; DoFairyStuff(player, 0); // recalculate FairyMax Config.FairyMax = (int)ceil((float)ClientList.size() / 50.0); //(1 fairy more every 50 player) } if(player->Party->party!=NULL) { CParty* party = player->Party->party; BEGINPACKET( pak, 0x7d2 ); ADDWORD ( pak, 0xff00 ); ADDDWORD ( pak, player->CharInfo->charid ); bool pflag = false; party->RemovePlayer( player ); if(party->Members.size()>1) { for(UINT i=0;i<party->Members.size();i++) { CPlayer* othermember = party->Members.at(i); if(!pflag) { ADDDWORD( pak, othermember->CharInfo->charid ); if(player->Party->IsMaster) othermember->Party->IsMaster = true; pflag = true; } othermember->client->SendPacket( &pak ); } } else { for(UINT i=0;i<party->Members.size();i++) { CPlayer* othermember = party->Members.at(i); BEGINPACKET( pak, 0x7d1 ); ADDBYTE ( pak, 0x05 ); ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, 0x0000 ); othermember->client->SendPacket( &pak ); othermember->Party->party = NULL; othermember->Party->IsMaster = true; } RemoveParty( party ); delete party; party = NULL; } } DB->QExecute("UPDATE accounts SET online=false where id=%u", player->Session->userid ); }
// Spawn a monster //LMA: added handling of skill summons. void CMonster::SpawnMonster( CPlayer* player, CMonster* thismon ) { BEGINPACKET( pak, 0x792 ); //struct tag_ADD_CHAR ADDWORD ( pak, clientid ); ADDFLOAT ( pak, Position->current.x*100 ); ADDFLOAT ( pak, Position->current.y*100 ); //current X and Y position if((thismon->bonushp > 0 || thismon->bonusmp > 0) && (thismon->skillid > 0)) //What is this? It seems to be sending this in place of destination if the monster is not able to move. Bonfires and so on { ADDFLOAT ( pak, 0xcdcdcdcd ); ADDFLOAT ( pak, 0xcdcdcdcd ); } else { ADDFLOAT ( pak, Position->destiny.x*100 ); //Destination position. This should always follow current position ADDFLOAT ( pak, Position->destiny.y*100 ); } // next 2 WORDS are m_wCommand and m_wTargetOBJ if(IsDead( )) { ADDWORD ( pak, 0x0003 ); ADDWORD ( pak, 0x0000 ); } else if(IsOnBattle( )) { //LMA: for supportive summons (lucky ghost...) if(Battle->bufftarget == Battle->target) { ADDWORD ( pak, 0x0002 ); ADDWORD ( pak, 0x0000 ); } else { ADDWORD ( pak, 0x0002 ); ADDWORD ( pak, Battle->target ); } } else if(IsMoving( )) { ADDWORD ( pak, 0x0001 ); ADDWORD ( pak, 0x0000 ); } else { ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, 0x0000 ); } ADDBYTE ( pak, thisnpc->stance ); ADDWORD ( pak, Stats->HP ); ADDWORD ( pak, 0x0000 ); // now Team Number if(thismon->owner != player->clientid) { CMap* map = GServer->MapList.Index[Position->Map]; //LMA: adding team... if (thismon->team!=0) { ADDWORD( pak,thismon->team); } else { if(IsSummon( ) && map->allowpvp!=0) { //Hostil ADDWORD( pak, 0x0064 ); } else if (IsSummon( ) && map->allowpvp==0) { //Friendly ADDWORD ( pak, 0x0000 ); } else { //Hostil ADDWORD( pak, 0x0064 ); } } } else { //Friendly ADDWORD( pak, 0x0000 ); } ADDWORD ( pak, 0x0000 ); //and finally DWORD StatusFlag ADDDWORD( pak, GServer->BuildBuffs( this ) ); //struct gsv_MOB_CHAR ADDWORD ( pak, montype ); ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, thismon->Stats->Level ); ADDWORD ( pak, thismon->Stats->Size ); player->client->SendPacket( &pak ); //LMA: supportive summons (lucky ghost) //PY: Another special case. Will probably need to remove this later if(IsSummon() && buffid > 0 && (player == GetOwner())) { Log(MSG_INFO,"The summon is spawned"); /*CPlayer* player = GetOwner( ); if (ownplayer==NULL) return true;*/ StartAction( player,SUMMON_BUFF,buffid); Log(MSG_INFO,"completly"); buffid=0; //only one buff } }
// Spawn a monster //LMA: added handling of skill summons. void CMonster::SpawnMonster( CPlayer* player, CMonster* thismon ) { BEGINPACKET( pak, 0x792 ); ADDWORD ( pak, clientid ); ADDFLOAT ( pak, Position->current.x*100 ); ADDFLOAT ( pak, Position->current.y*100 ); ADDDWORD ( pak, 0xcdcdcdcd ); ADDDWORD ( pak, 0xcdcdcdcd ); if(IsDead( )) { ADDWORD ( pak, 0x0003 ); ADDWORD ( pak, 0x0000 ); } else if(IsOnBattle( )) { //LMA: for supportive summons (lucky ghost...) if(Battle->bufftarget==Battle->target) { ADDWORD ( pak, 0x0002 ); ADDWORD ( pak, 0x0000 ); } else { ADDWORD ( pak, 0x0002 ); ADDWORD ( pak, Battle->target ); } } else if(IsMoving( )) { ADDWORD ( pak, 0x0001 ); ADDWORD ( pak, 0x0000 ); } else { ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, 0x0000 ); } if(IsSummon( ) ) { ADDBYTE ( pak, 0x01 ); } else { ADDBYTE ( pak, 0x00 ); } ADDWORD(pak, 0x0000); if(Stats->HP > MAXHPMOB) { Stats->HP = (long long) MAXHPMOB; } ADDDWORD ( pak, Stats->HP ); if(thismon->owner != player->clientid) { CMap* map = GServer->MapList.Index[Position->Map]; if (thismon->team!=0) { ADDDWORD( pak,thismon->team); } else { if(IsSummon( ) && map->allowpvp!=0) { //Hostil ADDDWORD( pak, 0x00000064 ); } else if (IsSummon( ) && map->allowpvp==0) { //Friendly ADDDWORD ( pak, 2 ); } else { //Hostil ADDDWORD( pak, 0x00000064 ); } } } else { //Friendly ADDDWORD( pak, 2 ); } ADDDWORD( pak, GServer->BuildBuffs( this ) ); ADDDWORD ( pak, montype ); if(IsSummon( )) { ADDWORD( pak, owner ); if (thismon->skillid>0) { ADDWORD( pak, thismon->skillid ); //id del skill (si es summon de skill) } else { ADDWORD( pak, 0x0000 ); //id del skill (si es summon de skill) } } player->client->SendPacket( &pak ); //LMA: supportive summons (lucky ghost) if(IsSummon()&&buffid>0&&(player==GetOwner())) { Log(MSG_INFO,"The summon is spawned"); StartAction( player,SUMMON_BUFF,buffid); Log(MSG_INFO,"completly"); buffid=0; //only one buff } }
// Party Actions [invite/leave/kick] bool CWorldServer::pakPartyActions( CPlayer* thisclient, CPacket* P ) { unsigned int action = GETBYTE((*P),0); CMap* map = MapList.Index[thisclient->Position->Map]; switch(action) { case 0x00://Invita a new party case 0x01://invite a existent party { UINT clientid = GETWORD((*P),1); if(thisclient->Party->party!=NULL) { //LMA: Refreshing Capacity if needed thisclient->Party->party->RefreshMax(); if(thisclient->Party->party->Members.size()>=thisclient->Party->party->Capacity) { SendSysMsg( thisclient, "Party is full" ); return true; } } CPlayer* otherclient = map->GetPlayerInMap( clientid );// have to be in same map if(otherclient==NULL) { BEGINPACKET( pak, 0x7d1 ); ADDBYTE ( pak, 0x00 );//No encontro el ID ADDWORD ( pak, clientid ); ADDBYTE ( pak, 0x00 ); thisclient->client->SendPacket( &pak ); return true; } if(otherclient->Party->party!=NULL) { BEGINPACKET( pak, 0x7d1 ); ADDBYTE ( pak, 0x01 );//No puede ser solicitado (ya tiene party) ADDWORD ( pak, clientid ); ADDBYTE ( pak, 0x00 ); thisclient->client->SendPacket( &pak ); return true; } if(abs(otherclient->Stats->Level-thisclient->Stats->Level)>(Config.Partygap+1)) { BEGINPACKET( pak, 0x7d1 ); ADDBYTE ( pak, 0x07 );//Level inapropiado ADDWORD ( pak, clientid ); ADDBYTE ( pak, 0x00 ); thisclient->client->SendPacket( &pak ); return true; } BEGINPACKET( pak, 0x7d0 ); ADDBYTE ( pak, action ); ADDWORD ( pak, thisclient->clientid ); ADDBYTE ( pak, 0x00 ); otherclient->client->SendPacket( &pak ); } break; case 0x02://Leave Party { if(thisclient->Party->party==NULL) return true; CParty* party = thisclient->Party->party; BEGINPACKET( pak, 0x7d2 ); ADDWORD ( pak, 0xff00 ); ADDDWORD ( pak, thisclient->CharInfo->charid ); bool pflag = false; if(!party->RemovePlayer( thisclient )) //if this player is not in this party return true; if(party->Members.size()>1) { for(UINT i=0;i<party->Members.size();i++) { CPlayer* thismember = party->Members.at(i); if(!pflag) { ADDDWORD( pak, thismember->CharInfo->charid ); if(thisclient->Party->IsMaster) thismember->Party->IsMaster = true; pflag = true; } thismember->client->SendPacket( &pak ); } } else { for(UINT i=0;i<party->Members.size();i++) { CPlayer* thismember = party->Members.at(i); BEGINPACKET( pak, 0x7d1 ); ADDBYTE ( pak, 0x05 ); ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, 0x0000 ); thismember->client->SendPacket( &pak ); thismember->Party->party = NULL; thismember->Party->IsMaster = true; } RemoveParty( party ); delete party; } } break; case 0x03: //Tomiz: Give leader New Way { if(thisclient->Party->party==NULL) return true; unsigned int clientid = GETWORD((*P),1); if ( !thisclient->Party->IsMaster || clientid == thisclient->clientid ) return true; CPlayer* otherclient = GetClientByID( clientid ); if(otherclient==NULL) return true; BEGINPACKET(pak, 0x7d1); ADDBYTE(pak, 8); ADDWORD(pak, otherclient->clientid); ADDWORD(pak, 0); otherclient->Party->IsMaster = true; thisclient->Party->IsMaster = false; thisclient->Party->party->SendToMembers( &pak ); } break; case 0x81: //Kick from party { unsigned int charid = GETDWORD((*P),1); if(thisclient->Party->party==NULL) return true; if(!thisclient->Party->IsMaster || thisclient->CharInfo->charid==charid) return true; CParty* party = thisclient->Party->party; CPlayer* thismember = party->GetMemberByCharID( charid ); if(thismember==NULL) return true; BEGINPACKET( pak, 0x7d1 ); // Kicked from party message ADDBYTE ( pak, 0x80 ); ADDDWORD ( pak, thismember->CharInfo->charid ); thismember->client->SendPacket( &pak ); RESETPACKET( pak, 0x7d2 ); ADDWORD ( pak, 0xff00 ); ADDDWORD ( pak, thismember->CharInfo->charid ); bool pflag = false; if(!party->RemovePlayer( thismember )) //if this player is not in this party return true; if(party->Members.size()>1) { for(UINT i=0;i<party->Members.size();i++) { CPlayer* othermember = party->Members.at(i); if(!pflag) { ADDDWORD( pak, othermember->CharInfo->charid ); if(thismember->Party->IsMaster) othermember->Party->IsMaster = true; pflag = true; } othermember->client->SendPacket( &pak ); } } else { for(UINT i=0;i<party->Members.size();i++) { CPlayer* othermember = party->Members.at(i); BEGINPACKET( pak, 0x7d1 ); ADDBYTE ( pak, 0x05 ); ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, 0x0000 ); othermember->client->SendPacket( &pak ); othermember->Party->party = NULL; othermember->Party->IsMaster = true; } RemoveParty( party ); delete party; } } break; default: Log(MSG_WARNING,"Party unknown action: %i", action); } return true; }
// Spawn a monster //LMA: added handling of skill summons. void CMonster::SpawnMonster( CPlayer* player, CMonster* thismon ) { BEGINPACKET( pak, 0x792 ); ADDWORD ( pak, clientid ); ADDFLOAT ( pak, Position->current.x*100 ); ADDFLOAT ( pak, Position->current.y*100 ); if((thismon->bonushp>0||thismon->bonusmp>0)&&(thismon->skillid>0)) { ADDFLOAT ( pak, 0xcdcdcdcd ); ADDFLOAT ( pak, 0xcdcdcdcd ); } else { ADDFLOAT ( pak, Position->destiny.x*100 ); ADDFLOAT ( pak, Position->destiny.y*100 ); } if(IsDead( )) { ADDWORD ( pak, 0x0003 ); ADDWORD ( pak, 0x0000 ); } else if(IsOnBattle( )) { //LMA: for supportive summons (lucky ghost...) if(Battle->bufftarget==Battle->target) { ADDWORD ( pak, 0x0002 ); ADDWORD ( pak, 0x0000 ); } else { ADDWORD ( pak, 0x0002 ); ADDWORD ( pak, Battle->target ); } } else if(IsMoving( )) { ADDWORD ( pak, 0x0001 ); ADDWORD ( pak, 0x0000 ); } else { ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, 0x0000 ); } if(IsSummon( ) ) { ADDBYTE ( pak, 0x01 ); } else { ADDBYTE ( pak, 0x00 ); } //LMA: Little check, for now we "only" have a DWORD for monster's HP so there is a limit //broken by some monsters (Turak boss) if(Stats->HP>MAXHPMOB) { LogDebugPriority(3); LogDebug("Too much HP for monster %i (%I64i->%I64i)",thismon->montype,Stats->HP,MAXHPMOB); LogDebugPriority(4); Stats->HP=(long long) MAXHPMOB; } ADDDWORD ( pak, Stats->HP ); if(thismon->owner != player->clientid) { CMap* map = GServer->MapList.Index[Position->Map]; //LMA: adding team... if (thismon->team!=0) { ADDDWORD( pak,thismon->team); } else { if(IsSummon( ) && map->allowpvp!=0) { //Hostil ADDDWORD( pak, 0x00000064 ); } else if (IsSummon( ) && map->allowpvp==0) { //Friendly ADDDWORD ( pak, 0x00000000 ); } else { //Hostil ADDDWORD( pak, 0x00000064 ); } //TODO: LMA, test if necessary or not anymore... /* else if(thismon->montype>=1474&&thismon->montype<=1489) { //LMA: Xmas trees are friendly. ADDDWORD ( pak, 0x00000000 ); } */ } } else { //Friendly ADDDWORD( pak, 0x00000000 ); } ADDDWORD( pak, GServer->BuildBuffs( this ) ); ADDWORD ( pak, montype ); ADDWORD ( pak, 0x0000 ); if(IsSummon( )) { ADDWORD( pak, owner ); if (thismon->skillid>0) { ADDWORD( pak, thismon->skillid ); //id del skill (si es summon de skill) } else { ADDWORD( pak, 0x0000 ); //id del skill (si es summon de skill) } } player->client->SendPacket( &pak ); //LMA: supportive summons (lucky ghost) if(IsSummon()&&buffid>0&&(player==GetOwner())) { Log(MSG_INFO,"The summon is spawned"); /*CPlayer* player = GetOwner( ); if (ownplayer==NULL) return true;*/ StartAction( player,SUMMON_BUFF,buffid); Log(MSG_INFO,"completly"); buffid=0; //only one buff } }
// Party Manager bool CWorldServer::pakPartyManager( CPlayer* thisclient, CPacket* P ) { unsigned int action = GETBYTE((*P),0); switch(action) { case 0x02://Acepto { if(thisclient->Party->party!=NULL)// have party return true; unsigned int clientid = GETWORD((*P),1); if (clientid == thisclient->clientid) { Log(MSG_WARNING, "User %s tried to party with himself\n", thisclient->CharInfo->charname); return false; //kick the cheater } CPlayer* otherclient = GetClientByID( clientid, thisclient->Position->Map ); if(otherclient==NULL) { BEGINPACKET( pak, 0x7d1 ); ADDBYTE ( pak, 0x00 );//No encontro el ID ADDWORD ( pak, clientid ); ADDBYTE ( pak, 0x00 ); thisclient->client->SendPacket( &pak ); return true; } CParty* party = otherclient->Party->party; if(party!=NULL) { //LMA: Refreshing Capacity if needed party->RefreshMax(); if(party->Members.size()>=party->Capacity) { SendSysMsg( thisclient, "Party is Full" ); return true; } } if(abs(otherclient->Stats->Level-thisclient->Stats->Level)>(Config.Partygap+1)) { BEGINPACKET( pak, 0x7d1 ); ADDBYTE ( pak, 0x07 );//Level inapropiado ADDWORD ( pak, clientid ); ADDBYTE ( pak, 0x00 ); thisclient->client->SendPacket( &pak ); return true; } BEGINPACKET( pak, 0x7d1 ); ADDBYTE ( pak, 0x02 );//Acepto Party ADDWORD ( pak, otherclient->clientid ); ADDBYTE ( pak, 0x00 ); otherclient->client->SendPacket( &pak ); if( party==NULL ) { // new party CParty* thisparty = new CParty; thisparty->AddPlayer( otherclient ); AddParty( thisparty ); otherclient->Party->IsMaster = true; party = thisparty; } //Send Party Level and Party Exp RESETPACKET( pak, 0x7d4 ); // ADDBYTE ( pak, party->PartyLevel ); ADDDWORD ( pak, party->Exp ); thisclient->client->SendPacket( &pak ); thisclient->Party->IsMaster = false; // Send New Party Member info to other players RESETPACKET( pak, 0x7d2 ); ADDBYTE ( pak, party->Option ); ADDBYTE ( pak, 0x01 ); ADDDWORD ( pak, thisclient->CharInfo->charid ); ADDWORD ( pak, thisclient->clientid ); ADDWORD ( pak, thisclient->Stats->MaxHP ); ADDWORD ( pak, thisclient->Stats->HP ); //ADDDWORD ( pak, 0x00000000 );//Tomiz: Was not commented before ADDDWORD ( pak, BuildBuffs( thisclient ));//Tomiz: Buff Data //ADDDWORD ( pak, 0x0000000f );//Tomiz: Was not commented before ADDDWORD ( pak, 0x1f40008c );//Tomiz ADDWORD ( pak, 0x1388 ); ADDSTRING ( pak, thisclient->CharInfo->charname ); ADDBYTE ( pak, 0x00 ); party->SendToMembers( &pak ); // Send To New Party Member the members List RESETPACKET( pak, 0x7d2 ); ADDBYTE ( pak, party->Option ); ADDBYTE ( pak, party->Members.size() ); for(int i=0;i<party->Members.size();i++) { CPlayer* member= party->Members.at(i); ADDDWORD ( pak, member->CharInfo->charid ); ADDWORD ( pak, member->clientid ); ADDWORD ( pak, member->Stats->MaxHP ); ADDWORD ( pak, member->Stats->HP ); //ADDDWORD ( pak, 0x00000000 );//Tomiz: Was not commented before ADDDWORD ( pak, BuildBuffs( member ));//Tomiz: Buff Data //ADDDWORD ( pak, 0x0000000f );//Tomiz: Was not commented before ADDDWORD ( pak, 0x7200005b );//Tomiz ADDWORD ( pak, 0x1388 ); ADDSTRING ( pak, member->CharInfo->charname ); ADDBYTE ( pak, 0x00 ); } thisclient->client->SendPacket( &pak ); party->AddPlayer( thisclient ); } break; case 0x04://No acepto { unsigned int clientid = GETWORD((*P),1); CPlayer* otherclient = GetClientByID( clientid, thisclient->Position->Map ); if(otherclient==NULL) { BEGINPACKET( pak, 0x7d1 ); ADDBYTE ( pak, 0x00 );//No encontro el ID ADDWORD ( pak, clientid ); ADDBYTE ( pak, 0x00 ); thisclient->client->SendPacket( &pak ); return true; } BEGINPACKET( pak, 0x7d1 ); ADDBYTE ( pak, 0x04 );//No acepto ADDWORD ( pak, thisclient->clientid ); ADDBYTE ( pak, 0x00 ); otherclient->client->SendPacket( &pak ); } break; default: Log(MSG_WARNING,"Party Manager unknown action: %i", action); } return true; }