void CMap::UpdateArena( CPlayer* thisclient ) { if(thisclient== NULL || thisclient->Groupga->Groupga == NULL) return; GAGroup* thisgroup = thisclient->Groupga->Groupga; int fragments = -1; for( UINT i=0; i< MonsterList.size();i++) { CMonster* thismon = MonsterList.at(i); if(thismon->team == thisgroup->GroupId && thismon->montype == 3708) fragments++; } Log(MSG_INFO,"called updatearena fragments = %i",fragments); if(fragments == 7) { for(UINT i=0;i<NPCList.size();i++) { CNPC* thisnpc = NPCList.at(i); if(thisnpc->thisnpc->id == 3704 && thisnpc->pos.x > 5160 && thisnpc->pos.x < 5170 && thisnpc->pos.y > 4915 && thisnpc->pos.y < 4925 && thisnpc->team == thisgroup->GroupId) { Log(MSG_INFO,"remove wall"); DeleteNPC(thisnpc); BEGINPACKET( pak, 0x794 ); ADDWORD( pak, thisnpc->clientid ); GServer->SendToVisible( &pak, thisclient ); RESETPACKET( pak, 0x799 ); ADDWORD ( pak, thisnpc->clientid ); ADDWORD ( pak, thisnpc->clientid ); ADDDWORD ( pak, 0 ); ADDDWORD ( pak, 16 ); GServer->SendToVisible( &pak, thisclient ); break; } } BEGINPACKET( pak, 0x7f8 ); ADDSTRING ( pak, "HUD_DawnSea_Destroyed_Gate1" ); ADDBYTE ( pak, 0x00 ); thisgroup->SendToMembers(&pak); } if(fragments == 0) { for(UINT i=0;i<NPCList.size();i++) { CNPC* thisnpc = NPCList.at(i); if(thisnpc->npctype == 3704 && thisnpc->pos.x == 5167 && thisnpc->pos.x == 4920 && thisnpc->team == thisgroup->GroupId) DeleteNPC(thisnpc); break; } BEGINPACKET( pak, 0x7f8 ); ADDSTRING ( pak, "HUD_DawnSea_Destroyed_Gate2" ); ADDBYTE ( pak, 0x00 ); thisgroup->SendToMembers(&pak); } }
// delete/resurect character bool CCharServer::pakDeleteChar( CCharClient* thisclient, CPacket* P ) { if(!thisclient->isLoggedIn) return false; char* name = (char*)&P->Buffer[2]; MYSQL_RES *result; MYSQL_ROW row; result = DB->QStore("SELECT account_name FROM characters WHERE char_name='%s' LIMIT 1", name); if(result==NULL) return false; row = mysql_fetch_row(result); if (strcmp(row[0], thisclient->username)!=0) { Log(MSG_HACK, "User %s tried deleting another users (%s) character.", thisclient->username, name); DB->QFree( ); return false; } DB->QFree( ); short int action = GETBYTE((*P), 1 ); unsigned long int DeleteTime = 0; switch(action) { case 0x00://Resurect { DeleteTime = 0; if(!DB->QExecute(" UPDATE characters SET deletetime=0 WHERE char_name='%s'", (char*)&P->Buffer[2] )) return false; } break; case 0x01://Delete { DeleteTime = GetServerTime( ) + Config.DeleteTime; if(!DB->QExecute(" UPDATE characters SET deletetime=%i WHERE char_name='%s'", DeleteTime, (char*)&P->Buffer[2] )) return false; } break; } BEGINPACKET( pak, 0x714 ); if(DeleteTime > 0 ) { ADDDWORD ( pak, Config.DeleteTime ); } else { ADDDWORD ( pak, 0x00000000 ); } ADDSTRING ( pak, (char*)&P->Buffer[2] ); ADDBYTE ( pak, 0x00 ); thisclient->SendPacket( &pak ); return true; }
// 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) { CMobGroup* thisgroup = GServer->GetMobGroup( monster->Position->respawn, monster->Position->Map ); if(thisgroup!=NULL) { /*if(thisgroup->active >= thisgroup->limit)// reset spawn timer if the spawn is full thisgroup->lastRespawnTime = clock();*/ //LMA: only if the monster isn't tactical... if(!monster->is_tactical) { thisgroup->active--; thisgroup->basicKills++; thisgroup->lastKills++; } } } 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; }
// Messenger Chat bool CCharServer::pakMessengerChat ( CCharClient* thisclient, CPacket* P ) { //WORD id = GETWORD((*P),0); DWORD id = GETDWORD((*P),0); char* message = new char[P->Size-41]; if(message==NULL) { Log(MSG_ERROR, "Error allocing memory: pakMessengerChat" ); return false; } memcpy( message, &P->Buffer[35], P->Size-41 ); CCharClient* otherclient = (CCharClient*) GetClientByID(id); if(otherclient!=NULL) { BEGINPACKET( pak, 0x7e2 ); /*ADDWORD ( pak, thisclient->charid ); ADDWORD ( pak, 0x0000 );*/ ADDDWORD ( pak, thisclient->charid ); ADDSTRING ( pak, thisclient->charname ); UINT namesize = strlen(thisclient->charname); for (int i=0;i<30-namesize;i++) ADDBYTE ( pak, 0x00 ); ADDBYTE ( pak, 0x00 ); ADDSTRING ( pak, message ); ADDBYTE ( pak, 0x00 ); otherclient->SendPacket(&pak); } delete []message; return true; }
// 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 ); } //LMA: resetting chatroom ID. DisconnectClientFromChat(thisclient); return true; }
bool CCharServer::pakDownloadCM ( CCharClient* thisclient, CPacket* P ) { unsigned int clanid = GETDWORD((*P), 0 ); MYSQL_RES* result = DB->QStore("SELECT logo FROM list_clan WHERE id=%i",clanid ); if(result==NULL) return true; if(mysql_num_rows(result)!=1) return true; MYSQL_ROW row = mysql_fetch_row(result); unsigned int cmid = atoi(row[0]); DB->QFree( ); char filename[30]; sprintf( filename, "clanmark/%u.cm", cmid ); FILE* fh = fopen( filename, "rb" ); if(fh==NULL) { Log( MSG_WARNING, "Invalid clanmark ID %i", cmid ); return true; } CClans* thisclan = GetClanByID(thisclient->clanid); BEGINPACKET( pak, 0x7e7 ); ADDDWORD ( pak, clanid ); while(!feof(fh)) { unsigned char charvalue = '\0'; fread( &charvalue, 1 , 1, fh ); ADDBYTE( pak, charvalue ); } ADDWORD( pak,0); thisclient->SendPacket( &pak ); fclose(fh); return true; }
// Disconnect client from char/world server bool CCharServer::pakLoginDSClient( CCharClient* thisclient, CPacket* P ) { unsigned int userid = GETDWORD((*P), 1 ); CCharClient* otherclient = GetClientByUserID( userid ); BYTE action = GETBYTE((*P),0); switch(action) { case 1: { if(otherclient==NULL) { Log( MSG_WARNING, "Userid '%u' is not online", userid ); return true; } otherclient->isLoggedIn = false; otherclient->isActive = false; BEGINPACKET( pak, 0x502 ); ADDBYTE ( pak, 1 ); ADDDWORD ( pak, userid ); //ADDBYTE ( pak, 0x00 ); //cryptPacket( (char*)&pak, NULL ); CChanels* thischannel = GetChannelByID( otherclient->channel ); if(thischannel!=NULL) send( thischannel->sock, (char*)&pak, pak.Size, 0 ); } break; } return true; }
// check if player can level up bool CPlayer::CheckPlayerLevelUP( ) { if (CharInfo->Exp >= GetLevelEXP()) { CharInfo->Exp -= GetLevelEXP(); Stats->Level++; Stats->HP = GetMaxHP( ); Stats->MP = GetMaxMP( ); CharInfo->StatPoints += int((Stats->Level * 0.8) + 10); //if(Stats->Level>=10) CharInfo->SkillPoints += ((Stats->Level + 2) / 2); BEGINPACKET( pak, 0x79e ); ADDWORD( pak, clientid ); ADDWORD( pak, Stats->Level ); ADDDWORD( pak, CharInfo->Exp ); ADDWORD( pak, CharInfo->StatPoints ); ADDWORD( pak, CharInfo->SkillPoints ); client->SendPacket( &pak ); RESETPACKET( pak, 0x79e ); ADDWORD( pak, clientid ); GServer->SendToVisible( &pak, this ); SetStats( ); //SendLevelUPtoChar(this); return true; } return false; }
// Send server list bool CLoginServer::pakGetServers( CLoginClient* thisclient, CPacket* P ) { if( !thisclient->isLoggedIn ) return false; MYSQL_ROW row; DWORD servernum = GETDWORD( (*P), 0 ); MYSQL_RES *result = DB->QStore( "SELECT id,name,connected,maxconnections FROM channels WHERE owner=%i and type=2", servernum ); if(result==NULL) return false; BEGINPACKET( pak, 0x704 ); ADDDWORD ( pak, servernum ); ADDBYTE ( pak, (BYTE)mysql_num_rows( result ) ); while(row = mysql_fetch_row(result)) { unsigned int status = (atoi(row[2]) * 100) / atoi(row[3]); ADDWORD( pak, atoi( row[0])); ADDBYTE( pak, 0 ); ADDWORD( pak, status ); ADDSTRING( pak, row[1]); ADDBYTE( pak, 0 ); } DB->QFree( ); thisclient->SendPacket ( &pak ); return true; }
// Send server list bool CLoginServer::pakGetServers( CLoginClient* thisclient, CPacket* P ) { if( !thisclient->isLoggedIn ) return false; MYSQL_ROW row; DWORD servernum = GETDWORD( (*P), 0 ); MYSQL_RES *result = DB->QStore( "SELECT id,name,connected,maxconnections FROM channels WHERE owner=%i and type=2", servernum ); if(result==NULL) return false; BEGINPACKET( pak, 0x704 ); ADDDWORD ( pak, servernum ); ADDBYTE ( pak, (BYTE)mysql_num_rows( result ) ); while(row = mysql_fetch_row(result)) { UINT connected = atoi(row[2]); UINT maxconnections = atoi(row[3]); BYTE id = atoi( row[0] ); string name = row[1]; //BYTE status = (((100 * connected) / maxconnections==0?1:maxconnections) / 5) & 0xff; unsigned int status = (connected * 100) / maxconnections; ADDWORD( pak, id ); ADDBYTE( pak, 0 ); ADDWORD( pak, status ); ADDSTRING( pak, name.c_str() ); ADDBYTE( pak, 0 ); } DB->QFree( ); thisclient->SendPacket ( &pak ); 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,connected,maxconnections 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); UINT connected = atoi(row[4]); UINT maxconnections = atoi(row[5]); ADDBYTE( pak, 0 ); ADDDWORD( pak, thisclient->userid ); ADDDWORD( pak, 0x87654321 ); if(strcmp(thisclient->ClientSubNet,row[3])==0)//from lan { ADDSTRING( pak, row[2] ); Log(MSG_INFO, "Lan: %s choice channel #%i", thisclient->username.c_str(), channelnum); } else if(strcmp( thisclient->ClientSubNet ,"127.0.0")==0)//same computer { ADDSTRING( pak, "127.0.0.1" ); Log(MSG_INFO, "Server: %s choice channel #%i", thisclient->username.c_str(), channelnum); } else { ADDSTRING( pak, row[0] ); Log(MSG_INFO, "Inet: %s choice channel #%i", thisclient->username.c_str(), channelnum); } ADDBYTE( pak, 0 ); ADDWORD( pak, atoi(row[1]) ); DB->QFree( ); thisclient->SendPacket ( &pak ); return true; }
// 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 ); ADDWORD ( pak, 0x0000 ); ADDDWORD ( pak, 0xcdcdcdcd ); ADDDWORD ( pak, 0xcdcdcdcd ); ADDDWORD ( pak, 0xcdcdcdcd ); ADDDWORD ( pak, 0xcdcdcdcd ); ADDWORD ( pak, 0xcdcd ); ADDBYTE ( pak, 0xd3 ); thisclient->SendPacket( &pak ); return true; }
// 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; }
// 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; }
// Send Levelup To charserver bool CWorldServer::SendLevelUPtoChar(CPlayer *thisclient) { BEGINPACKET( pak, 0x79e ); //ADDWORD( pak, thisclient->CharInfo->charid ); ADDDWORD( pak, thisclient->CharInfo->charid ); ADDWORD( pak, thisclient->Stats->Level ); cryptPacket( (char*)&pak, NULL ); send( csock, (char*)&pak, pak.Size, 0 ); return true; }
// Change messenger status 07 - online | 08 - offline bool CCharServer::ChangeMessengerStatus (CCharClient* thisclient, CCharClient* otherclient, int status) { BEGINPACKET( pak, 0x7e1 ); ADDBYTE ( pak, 0x08 ); //ADDWORD ( pak, thisclient->charid ); //ADDWORD ( pak, 0x0000 ); ADDDWORD ( pak, thisclient->charid ); ADDBYTE ( pak, status ); otherclient->SendPacket(&pak); return true; }
//LMA: disconnect a client from chatroom. bool CCharServer::DisconnectClientFromChat( CCharClient* thisclientwc ) { //LMA: resetting chatroom ID. if(thisclientwc->chatroom_id!=0) { if(chatroom_list.find(thisclientwc->chatroom_id)!=chatroom_list.end()) { for (int k=0; k<chatroom_list[thisclientwc->chatroom_id]->People_list.size(); k++) { if(chatroom_list[thisclientwc->chatroom_id]->People_list.at(k)->charid==thisclientwc->charid) { //Deleting the guy from the chatroom list. chatroom_list[thisclientwc->chatroom_id]->People_list.erase(chatroom_list[thisclientwc->chatroom_id]->People_list.begin()+k); break; } } if (chatroom_list[thisclientwc->chatroom_id]->People_list.size()==0) { chatroom_list.erase(thisclientwc->chatroom_id); } else { //TODO: send a packet to other people to tell them this guy has deconnected from chatroom. for (int k=0; k<chatroom_list[thisclientwc->chatroom_id]->People_list.size(); k++) { CCharClient* otherclient=GetClientByID(chatroom_list[thisclientwc->chatroom_id]->People_list.at(k)->charid); if(otherclient==NULL) { continue; } BEGINPACKET( pak, 0x7e3 ); ADDBYTE ( pak, 0x16 ); ADDWORD ( pak, thisclientwc->userid ); ADDDWORD ( pak, thisclientwc->charid ); ADDSTRING ( pak, thisclientwc->charname ); ADDBYTE ( pak, 0x00 ); otherclient->SendPacket( &pak ); } } } thisclientwc->chatroom_id=0; } 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 ); }
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; }
// Connect WorldServer bool CCharServer::pakWSReady ( CCharClient* thisclient, CPacket* P ) { if(thisclient->isLoggedIn) return false; if(GETDWORD((*P),0) != Config.CharPass ) { Log( MSG_HACK, "WorldServer Tried to connect CharServer with wrong password "); return true; } thisclient->userid = GETDWORD((*P), 4); //our channelid thisclient->accesslevel = 0xffff; //this will identify thisclient as channel // add channel CChanels* newchannel = new (nothrow) CChanels; if(newchannel==NULL) return false; newchannel->id = GETDWORD((*P), 4); newchannel->ip = inet_ntoa( thisclient->clientinfo.sin_addr ); newchannel->port = GETWORD((*P),8 ); Log( MSG_INFO, "Channel #%i connected from ip %s", newchannel->id, newchannel->ip ); // Connect to charserver newchannel->sock = socket( AF_INET, SOCK_STREAM, 0 ); if (newchannel->sock == INVALID_SOCKET) { Log( MSG_WARNING, "Could not access worldserver IP: %s , Port: %i", newchannel->ip, newchannel->port ); delete newchannel; return false; } struct sockaddr_in ain; ain.sin_family = AF_INET; ain.sin_addr.s_addr = thisclient->clientinfo.sin_addr.s_addr; ain.sin_port = htons( newchannel->port ); memset(&(ain.sin_zero), '\0', 8); if ( connect( newchannel->sock , (SOCKADDR*) &ain, sizeof(ain) ) == SOCKET_ERROR) { Log( MSG_WARNING, "Could not access worldserver IP: %s , Port: %i", newchannel->ip , newchannel->port ); delete newchannel; return false; } ChannelList.push_back( newchannel ); thisclient->isLoggedIn = true; BEGINPACKET( pak, 0x500 ); ADDDWORD ( pak, Config.WorldPass ); //cryptPacket( (char*)&pak, NULL ); send( newchannel->sock, (char*)&pak, pak.Size, 0 ); return true; }
// Connect user to charserver bool CLoginServer::pakConnectToChar( CLoginClient* thisclient, CPacket *P ) { if(thisclient->isLoggedIn) return true; if(GETDWORD((*P),0) != Config.LoginPass) { Log( MSG_HACK, "Charserver Tried to connect loginserver with wrong password "); return true; } thisclient->userid = GETDWORD((*P), 4); //our serverid thisclient->accesslevel = 0xffff; //this will identify thisclient as server // add new server CServers* newserver = new (nothrow) CServers( ); if(newserver==NULL) return false; newserver->id = GETDWORD((*P), 4); newserver->ip = inet_ntoa( thisclient->clientinfo.sin_addr ); newserver->port = GETWORD((*P),8 ); Log( MSG_INFO, "Server #%i connected from ip %s", newserver->id, newserver->ip ); // Connect to charserver newserver->sock = socket( AF_INET, SOCK_STREAM, 0 ); if (newserver->sock == INVALID_SOCKET) { Log( MSG_WARNING, "Could not access char server IP: %s , Port: %i", newserver->ip, newserver->port ); delete newserver; return false; } struct sockaddr_in ain; ain.sin_family = AF_INET; ain.sin_addr.s_addr = thisclient->clientinfo.sin_addr.s_addr; ain.sin_port = htons( newserver->port ); if ( connect( newserver->sock , (SOCKADDR*) &ain, sizeof(ain) ) == SOCKET_ERROR) { Log( MSG_WARNING, "Could not access char server IP: %s , Port: %i", newserver->ip , newserver->port ); delete newserver; return false; } ServerList.push_back( newserver ); // Identify packet thisclient->isLoggedIn = true; BEGINPACKET( pak, 0x501 ); ADDDWORD ( pak, Config.CharPass ); cryptPacket( (char*)&pak, NULL ); send( newserver->sock, (char*)&pak, pak.Size, 0 ); return true; }
// check if player can level up bool CPlayer::CheckPlayerLevelUP( ) { if (CharInfo->Exp >= GetLevelEXP()) { CharInfo->Exp -= GetLevelEXP(); Stats->Level++; Stats->HP = GetMaxHP( ); Stats->MP = GetMaxMP( ); CharInfo->StatPoints += int((Stats->Level*0.8)+10); // Proper skill point distribution for Pre-Evo switch (Stats->Level) { case 10: case 14: CharInfo->SkillPoints += 2; break; case 18: CharInfo->SkillPoints += 3; break; case 22: CharInfo->SkillPoints += 4; break; } // 5 skill points every 4 levels from 22 if (Stats->Level > 22 && Stats->Level < 99 && ((Stats->Level - 22) % 4) == 0) CharInfo->SkillPoints += 5; // 5 skill points every 2 levels from 98 if (Stats->Level > 98 && (Stats->Level % 2) == 0) CharInfo->SkillPoints += 5; BEGINPACKET( pak, 0x79e ); ADDWORD( pak, clientid ); ADDWORD( pak, Stats->Level ); ADDDWORD( pak, CharInfo->Exp ); ADDWORD( pak, CharInfo->StatPoints ); ADDWORD( pak, CharInfo->SkillPoints ); client->SendPacket( &pak ); RESETPACKET( pak, 0x79e ); ADDWORD( pak, clientid ); GServer->SendToVisible( &pak, this ); SetStats( ); //SendLevelUPtoChar(this); return true; } 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; }
// 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 } }
// 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; }