// Party Chat bool CWorldServer::pakPartyChat( CPlayer* thisclient, CPacket* P ) { CParty* party = thisclient->Party->party; if(party==NULL) return true; BEGINPACKET( pak, 0x786 ); ADDWORD ( pak, thisclient->clientid ); ADDSTRING ( pak, P->Buffer ); ADDBYTE ( pak, 0 ); party->SendToMembers( &pak ); return true; }
// Change Party Options bool CWorldServer::pakPartyOption( CPlayer* thisclient, CPacket* P ) { if(!thisclient->Party->IsMaster) return true; CParty* party = thisclient->Party->party; if(party==NULL) return true; party->Option = GETBYTE((*P),0); BEGINPACKET( pak, 0x7d7 ); ADDBYTE ( pak, party->Option ); ADDBYTE ( pak, 0x00 ); party->SendToMembers( &pak ); return true; }
// 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; }
// Give Exp bool CWorldServer::GiveExp( CMonster* thismon ) { Log(MSG_DEBUG,"Awarding EXP"); int tmpMult = 1; if( thismon->owner != 0) // Summon { MapList.Index[thismon->Position->Map]->DeleteMonster( thismon ); return true; } // Give Experience Drops and Quest Items vector<CPartyExp*> PartyExp; vector<CParty*> PartyList; CMap* map = GServer->MapList.Index[thismon->Position->Map]; for(UINT i=0;i<thismon->PlayersDamage.size();i++) { MonsterDamage* thisplayer = thismon->PlayersDamage.at(i); CPlayer* thisclient = GetClientByCID( thisplayer->charid, thismon->Position->Map ); if( thisplayer->damage > 0 && thisclient != NULL ) //player did some damage { Log(MSG_DEBUG,"Player did %i damage. max = %i",thisplayer->damage,thismon->Stats->MaxHP); float MyPercent = (float)thisplayer->damage / thismon->Stats->MaxHP; if(MyPercent > thisclient->CharInfo->HighestOverkill) { thisclient->CharInfo->HighestOverkill = MyPercent; SendPM(thisclient, "Congratulations!! You have exceeded your highest ever Overkill rate. New Best: %f",thisclient->CharInfo->HighestOverkill); } if(MyPercent > GServer->Config.MaxOverkill)MyPercent = GServer->Config.MaxOverkill; //set overkill ceiling Log(MSG_DEBUG,"Percentage multiplier %f",MyPercent); if( thisclient->Battle->target == thismon->clientid ) { ClearBattle( thisclient->Battle ) thisclient->Position->destiny = thisclient->Position->current; //Log(MSG_DEBUG,"(GiveExp) Destiny set to current position X: %f Y: %f.",thisclient->Position->current.x,thisclient->Position->current.y); } if( thismon->MonsterDrop->firsthit == thisclient->CharInfo->charid ) { for( int q=0;q<10;q++) { // Give Quest Item if( thisclient->quest.quests[q].QuestID != 0 ) { Log(MSG_DEBUG,"Giving quest reward item for quest %i Killed monster type %i",thisclient->quest.quests[q].QuestID,thismon->montype); //P: Suppressing this completely for a test of the drop code added below //BEGINPACKET( pak, 0x731 ) //ADDWORD ( pak, thismon->montype ); //thisclient->client->SendPacket( &pak ); //PY: thismon->thisnpc->die_quest contains the hash needed to complete the trigger so we can just bypass the initial part of this process int success = thisclient->ExecuteQuestTrigger(thismon->thisnpc->die_quest); if(success == 5) // quest success { Log(MSG_DEBUG,"Death QSD Trigger %i successful. Sending success: ",thismon->thisnpc->die_quest); BEGINPACKET ( pak, 0x730); ADDBYTE ( pak, success); ADDBYTE ( pak, 0); ADDDWORD( pak, thismon->thisnpc->die_quest); thisclient->client->SendPacket(&pak); } break; } } } //assign my own exp for monsters that I personally damaged unsigned int exp = (unsigned int)floor(thismon->thisnpc->exp * MyPercent); //unsigned int exp = (unsigned int)ceil((double)((thismon->thisnpc->exp * thisplayer->damage) / (thismon->thisnpc->hp*thismon->thisnpc->level))); exp = exp * Config.EXP_RATE * map->mapXPRate; //calculate base exp for this client. No medals or stuff accounted for yet Log(MSG_DEBUG,"MonXP: %i config rate: %i Map rate : %i My percent: %f Total XP: %i", thismon->thisnpc->exp, Config.EXP_RATE, map->mapXPRate, MyPercent, exp); thisclient->CharInfo->Pending_Exp += (exp * thisclient->Stats->xprate); //store exp into thisclient's pending_exp using personal xprate adjustments Log(MSG_DEBUG,"My personal XPrate: %i ", thisclient->Stats->xprate); if( thisclient->Party->party!=NULL ) { //Log(MSG_DEBUG,"Player is in a party"); //player is in a party so scan the party members CParty* party = thisclient->Party->party; //assign a party if(party == NULL) return true; //Log(MSG_DEBUG,"party found. Counted = %i", party->counted); for(UINT p=0;p<party->Members.size();p++) //loop through all the members in the party { //Log(MSG_DEBUG,"member %i being parsed", p); if(!party->counted) { //Log(MSG_DEBUG,"party added to list. level = %i", party->PartyLevel); party->counted = true; //tag the party so we don't add it to the list twice PartyList.push_back( party ); //we will need this list later to convert pending exp to real exp } CPlayer* thismember = party->Members.at(p); //find a party member if(thismember == NULL) return true; float RawTmpExp = (exp * (party->PartyLevel + 25) / 50); unsigned int tempxp =(unsigned int)(floor)(RawTmpExp); if (tempxp < 1)tempxp = 1; //Log(MSG_DEBUG,"member %i pending exp = %i tempxp: %i", p, thismember->CharInfo->Pending_Exp, tempxp); thismember->CharInfo->Pending_Exp += tempxp; // add a percentage of thisclient's non-adjusted exp to all party members including himself //Log(MSG_DEBUG,"member %i pending exp (after tempxp) = %i", p, thismember->CharInfo->Pending_Exp); } if(party->PartyLevel < 50) //only give party exp if party level is under 50 { party->Pending_Exp += exp; //add thisclient's non-adjusted xp to the pending exp of the party } } else //not in a party so deal with all the exp now { //SendPM(thisclient, "You receive %i EXP",thisclient->CharInfo->Pending_Exp); //Log(MSG_DEBUG,"Player awarded %i experience points",thisclient->CharInfo->Pending_Exp); thisclient->CharInfo->Exp += thisclient->CharInfo->Pending_Exp; thisclient->CharInfo->Pending_Exp = 0; //if(!thisclient->CheckPlayerLevelUP()) if(thisclient->CharInfo->Exp < thisclient->GetLevelEXP()) { BEGINPACKET( pak, 0x79b ); ADDDWORD ( pak, thisclient->CharInfo->Exp ); ADDWORD ( pak, thisclient->CharInfo->stamina ); ADDWORD ( pak, thismon->clientid ); thisclient->client->SendPacket( &pak ); } } } } for(int p=0;p<PartyList.size();p++) //loop through our party list to assign final exp to all party members. We already did non-party members up there^ { CParty* thisparty = PartyList.at( p ); if(thisparty == NULL) { //Log(MSG_DEBUG,"Party not valid"); continue; } //Log(MSG_DEBUG,"Party %i exp: %i pending exp: %i", p, thisparty->Exp, thisparty->Pending_Exp ); thisparty->counted = false; //reset the boolean for next time for(UINT i=0;i<thisparty->Members.size();i++) //loop through all the members in the party { CPlayer* thismember = thisparty->Members.at(i); //find a party member if(thismember == NULL) return true; thismember->CharInfo->Exp += thismember->CharInfo->Pending_Exp; //Log(MSG_DEBUG,"Added pending exp %i to regular exp %i for member %i", thismember->CharInfo->Pending_Exp, thismember->CharInfo->Exp, i); thismember->CharInfo->Pending_Exp = 0; if(!thismember->CheckPlayerLevelUP( )) { BEGINPACKET( pak, 0x79b ); ADDDWORD ( pak, thismember->CharInfo->Exp ); ADDWORD ( pak, thismember->CharInfo->stamina ); //ADDWORD ( pak, 0 ); //PY: not needed ADDWORD ( pak, thismon->clientid ); thismember->client->SendPacket( &pak ); } } thisparty->Exp += thisparty->Pending_Exp; thisparty->Pending_Exp = 0; thisparty->m_bitLevelUP = 0; if( thisparty->Exp > GetMaxPartyExp(thisparty->PartyLevel)) //level up the party { thisparty->PartyLevel++; thisparty->Exp -= GetMaxPartyExp(thisparty->PartyLevel-1); thisparty->m_iEXP = thisparty->Exp; thisparty->m_bitLevelUP = 1; //set levelup bit. See client structure below } //PY: structure of 0x7d4 /* BYTE m_btLEVEL; struct { unsigned int m_iEXP : 31; unsigned int m_bitLevelUP : 1; } ; */ BEGINPACKET ( pak, 0x7d4 ); ADDBYTE ( pak, thisparty->PartyLevel ); ADDWORD ( pak, thisparty->m_iEXP ); // defined as 31 bits ADDWORD ( pak, thisparty->m_bitLevelUP ); // defined as 1 bit thisparty->SendToMembers( &pak ); } return true; }