/* Rose Online Server Emulator Copyright (C) 2006,2007 OSRose Team http://www.osrose.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. depeloped with Main erose/hrose source server + some change from the original eich source */ #include "player.h" #include "worldserver.h" // Returns the amount of exp that is needed for the next level UINT CPlayer::GetLevelEXP( ) { if (Stats->Level <= 15) return (unsigned int)( ( Stats->Level + 10 ) * ( Stats->Level + 5 ) * ( Stats->Level + 3 ) * 0.7 ); else if (Stats->Level <= 50) return (unsigned int)( ( Stats->Level - 5 ) * ( Stats->Level + 2 ) * ( Stats->Level + 2 ) * 2.2 ); else if (Stats->Level <= 100) return (unsigned int)( ( Stats->Level - 38 ) * ( Stats->Level - 5 ) * ( Stats->Level + 2 ) * 9 ); else if (Stats->Level <= 139) return (unsigned int)( ( Stats->Level + 220 ) * ( Stats->Level + 34 ) * ( Stats->Level + 27 ) ); else return (unsigned int)( ( Stats->Level - 126 ) * ( Stats->Level - 15 ) * ( Stats->Level + 7 ) * 41 ); } // check if player can level up bool CPlayer::CheckPlayerLevelUP( ) { //if(Session->Respawned == 2){Log( MSG_INFO, "Checking Levelup" );} if (CharInfo->Exp >= GetLevelEXP()) { //if(Session->Respawned == 2){Log( MSG_INFO, "XP >= GetLevelXP" );} CharInfo->Exp -= GetLevelEXP(); //exp is subtracted anyway whether we reached max or not. //check if max level has been reached if(Stats->Level >= GServer->Config.MaxLevel) { //posibly give extra bonuses here at some point rather than just subtracting exp and returning. return true; // returning true should show the levelup animation still and also set HP and MP to max } Stats->Level++; Stats->HP = GetMaxHP( ); Stats->MP = GetMaxMP( ); CharInfo->StatPoints += int((Stats->Level*0.8)+10); // Proper skill point distribution for Pre-Evo if(Stats->Level >= 100 && (Stats->Level % 2) == 0) { // 5 skill points every 2 levels from 100 CharInfo->SkillPoints += 5; } else if(Stats->Level > 22 && ((Stats->Level - 22) % 4) == 0) { // 5 skill points every 4 levels from 22 CharInfo->SkillPoints += 5; } else if(Stats->Level == 22) { CharInfo->SkillPoints += 4; } else if(Stats->Level == 18) { CharInfo->SkillPoints += 3; } else if(Stats->Level == 14 || Stats->Level == 10) { CharInfo->SkillPoints += 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( ); savedata( ); //SendLevelUPtoChar(this); return true; } //if(Session->Respawned == 2){Log( MSG_INFO, "XP < GetLevelXP" );} return false; } bool CPlayer::canUseSkill(CSkills* skill) { // Check for weapon requirements int check = 5; bool fail = true; for (int i = 0; i < 5; i++) { if (skill->weapon[i] == 0) { check--; continue; } for (int j = 1; j < 12; j++) { // I'm not sure if 1 - 12 is right for all equipment? if (GServer->EquipList[items[j].itemtype].Index[items[j].itemnum]->type == skill->weapon[i]) { fail = false; break; } } if (!fail) break; } if (fail && check) { if(Session->codedebug) //Debug code { char buffer[200]; sprintf ( buffer, "Failed skill check @ weapons. skill = %i", skill->id); GServer->SendPM(this, buffer); } return false; } // Check job requirement fail = true; check = 4; for (char i = 0; i < 4; i++) { if (skill->c_class[i]>0) { switch(skill->c_class[i]) { case cSoldierJob: if((CharInfo->Job)/100==1) fail = false; break; case cMuseJob: if((CharInfo->Job)/100==2) fail = false; break; case cHawkerJob: if((CharInfo->Job)/100==3) fail = false; break; case cDealerJob: if((CharInfo->Job)/100==4) fail = false; break; case cKnightJob: if(CharInfo->Job==121) fail = false; break; case cChampionJob: if(CharInfo->Job==122) fail = false; break; case cMageJob: if(CharInfo->Job==221) fail = false; break; case cClericJob: if(CharInfo->Job==222) fail = false; break; case cRaiderJob: if(CharInfo->Job==321) fail = false; break; case cScoutJob: if(CharInfo->Job==322) fail = false; break; case cBourgeoisJob: if(CharInfo->Job==421) fail = false; break; case cArtisanJob: if(CharInfo->Job==422) fail = false; break; default: break; } if (!fail) break; } else check--; } if (fail && check) { if(Session->codedebug) //Debug code { char buffer[200]; sprintf ( buffer, "Failed skill check @ job. job = %i skill = %i",CharInfo->Job, skill->id); GServer->SendPM(this, buffer); } return false; } // Check for stat requirements fail = false; for (char i = 0; i < 2; i++) { switch (skill->req[i]) { case sLevel: if (skill->reqam[i] > Stats->Level) fail = true; break; case sStrength: if (skill->reqam[i] > Attr->Str + Attr->Estr) fail = true; break; case sDexterity: if (skill->reqam[i] > Attr->Dex + Attr->Edex) fail = true; break; case sIntelligence: if (skill->reqam[i] > Attr->Int + Attr->Eint) fail = true; break; case sConcentration: if (skill->reqam[i] > Attr->Con + Attr->Econ) fail = true; break; case sCharm: if (skill->reqam[i] > Attr->Cha + Attr->Echa) fail = true; break; case sSensibility: if (skill->reqam[i] > Attr->Sen + Attr->Esen) fail = true; break; default: break; } } if (fail) { if(Session->codedebug) //Debug code { char buffer[200]; sprintf ( buffer, "Failed skill check @ stats. skill = %i", skill->id); GServer->SendPM(this, buffer); } return false; } if(Session->codedebug) //Debug code { char buffer[200]; sprintf ( buffer, "Skill check successful for skill = %i", skill->id); GServer->SendPM(this, buffer); } // Passed all the tests, can cast skill return true; } // Send a PM to client with user information bool CPlayer::GetPlayerInfo( ) { char text[50]; sprintf(text,"Attack: %i | Critical: %i",Stats->Attack_Power, Stats->Critical ); BEGINPACKET( pak, 0x0784 ); ADDSTRING( pak, "[GM]PlayerInfo" ); ADDBYTE( pak, 0 ); ADDSTRING( pak, text ); ADDBYTE( pak, 0 ); client->SendPacket(&pak); sprintf(text,"Defense: %i | Magic Defense: %i",Stats->Defense, Stats->Magic_Defense); RESETPACKET( pak, 0x0784 ); ADDSTRING( pak, "[GM]PlayerInfo" ); ADDBYTE( pak, 0 ); ADDSTRING( pak, text ); ADDBYTE( pak, 0 ); client->SendPacket(&pak); sprintf(text,"Accury: %i | Dodge: %i",Stats->Accury,Stats->Dodge ); RESETPACKET( pak, 0x0784 ); ADDSTRING( pak, "[GM]PlayerInfo" ); ADDBYTE( pak, 0 ); ADDSTRING( pak, text ); ADDBYTE( pak, 0 ); client->SendPacket(&pak); sprintf(text,"aspeed: %i | mspeed: %i",Stats->Attack_Speed,Stats->Move_Speed ); RESETPACKET( pak, 0x0784 ); ADDSTRING( pak, "[GM]PlayerInfo" ); ADDBYTE( pak, 0 ); ADDSTRING( pak, text ); ADDBYTE( pak, 0 ); client->SendPacket(&pak); sprintf(text,"HP: %i/%i , MP: %i/%i",Stats->HP,Stats->MaxHP,Stats->MP,Stats->MaxMP); RESETPACKET( pak, 0x0784 ); ADDSTRING( pak, "[GM]PlayerInfo" ); ADDBYTE( pak, 0 ); ADDSTRING( pak, text ); ADDBYTE( pak, 0 ); client->SendPacket(&pak); sprintf(text,"Position[%i]: (%.0f,%.0f)",Position->Map,Position->current.x,Position->current.y); RESETPACKET( pak, 0x0784 ); ADDSTRING( pak, "[GM]PlayerInfo" ); ADDBYTE( pak, 0 ); ADDSTRING( pak, text ); ADDBYTE( pak, 0 ); client->SendPacket(&pak); sprintf(text,"ClientID: %u | CharID: %u", clientid, CharInfo->charid ); RESETPACKET( pak, 0x0784 ); ADDSTRING( pak, "[GM]PlayerInfo" ); ADDBYTE( pak, 0 ); ADDSTRING( pak, text ); ADDBYTE( pak, 0 ); client->SendPacket(&pak); sprintf(text,"inGame: %i | Logged: %i", Session->inGame, Session->isLoggedIn ); RESETPACKET( pak, 0x0784 ); ADDSTRING( pak, "[GM]PlayerInfo" ); ADDBYTE( pak, 0 ); ADDSTRING( pak, text ); ADDBYTE( pak, 0 ); client->SendPacket(&pak); sprintf(text,"ClanName[%u]: %s | ClanGrade: %i | ClanRank: %i", Clan->clanid, Clan->clanname, Clan->grade, Clan->clanrank ); RESETPACKET( pak, 0x0784 ); ADDSTRING( pak, "[GM]PlayerInfo" ); ADDBYTE( pak, 0 ); ADDSTRING( pak, text ); ADDBYTE( pak, 0 ); client->SendPacket(&pak); return true; } // clearn player lists bool CPlayer::CleanPlayerVector( ) { CMap* map = GServer->MapList.Index[Position->Map]; VisiblePlayers.clear(); VisibleMonsters.clear(); VisibleDrops.clear(); VisibleNPCs.clear(); return true; } // update visibility list bool CPlayer::VisiblityList( ) { if(!this->Session->inGame) return true; std::vector newVisiblePlayers; std::vector newVisibleDrops; std::vector newVisibleMonsters; std::vector newVisibleNPCs; // Clients CMap* map = GServer->MapList.Index[Position->Map]; for(UINT i=0;iPlayerList.size();i++) { CPlayer* otherclient = map->PlayerList.at(i); if(otherclient == NULL) continue; if ( this == otherclient || !otherclient->Session->inGame) { continue; } float distance = GServer->distance( this->Position->current, otherclient->Position->current ); if ( GServer->IsVisible( this, otherclient ) ) { if ( distance < MAXVISUALRANGE && !otherclient->isInvisibleMode ) { newVisiblePlayers.push_back( otherclient ); } else { ClearObject( otherclient->clientid ); } } else { if ( distance < MINVISUALRANGE && !otherclient->isInvisibleMode ) { newVisiblePlayers.push_back( otherclient ); otherclient->SpawnToPlayer(this, otherclient); } } } // Monsters for(UINT i=0;iMonsterList.size();i++) { CMonster* thismon = map->MonsterList.at( i ); if(thismon == NULL) continue; float distance = GServer->distance ( this->Position->current, thismon->Position->current ); if ( GServer->IsVisible( this, thismon ) ) { if (distance < MAXVISUALRANGE ) { newVisibleMonsters.push_back( thismon->clientid); } else { ClearObject( thismon->clientid ); } } else { if ( distance< MINVISUALRANGE ) { newVisibleMonsters.push_back( thismon->clientid); thismon->SpawnMonster(this, thismon ); } } } // Drops for(unsigned i=0; iDropsList.size(); i++) { CDrop* thisdrop = map->DropsList.at(i); if(thisdrop == NULL) continue; if( time(NULL) - thisdrop->droptime <= GServer->Config.DropDelay ) continue; float distance = GServer->distance( this->Position->current, thisdrop->pos ); if ( GServer->IsVisible( this, thisdrop ) ) { if ( distance< MAXVISUALRANGE ) { newVisibleDrops.push_back( thisdrop ); } else { this->ClearObject( thisdrop->clientid ); } } else { if ( distance < MINVISUALRANGE ) { thisdrop->spawned = true; newVisibleDrops.push_back( thisdrop ); GServer->pakSpawnDrop( this, thisdrop ); } } } // Npcs for(unsigned i=0; iNPCList.size(); i++) { CNPC* thisnpc = map->NPCList.at(i); float distance = GServer->distance( this->Position->current, thisnpc->pos ); if ( GServer->IsVisible( this, thisnpc ) ) { if ( distance < MAXVISUALRANGE ) { newVisibleNPCs.push_back( thisnpc ); } else { this->ClearObject( thisnpc->clientid ); } } else { if ( distance < MINVISUALRANGE ) { newVisibleNPCs.push_back( thisnpc ); GServer->pakSpawnNPC( this, thisnpc ); } } } VisiblePlayers.clear(); VisibleDrops.clear(); VisibleMonsters.clear(); VisibleNPCs.clear(); VisiblePlayers = newVisiblePlayers; VisibleDrops = newVisibleDrops; VisibleMonsters = newVisibleMonsters; VisibleNPCs = newVisibleNPCs; return true; } bool CPlayer::ChangeDialog(unsigned int npc, unsigned int dialog, unsigned int eventid ) { CMap* map = GServer->MapList.Index[Position->Map]; if(map == NULL) return true; for(unsigned i=0; iNPCList.size(); i++) { CNPC* thisnpc = map->NPCList.at(i); if(thisnpc->npctype == npc) { //Log(MSG_INFO,"Found NPC %i with dialog %i",thisnpc->npctype, thisnpc->thisnpc->dialogid); CNPC* newnpc = thisnpc; this->ClearObject( thisnpc->clientid ); newnpc->thisnpc->dialogid = dialog; newnpc->thisnpc->eventid = eventid; GServer->ObjVar[npc][0] = eventid; VisibleNPCs.push_back( newnpc ); GServer->pakSpawnNPC( this, newnpc ); } } return true; } // Returns a free slot in the inventory (0xffff if is full) UINT CPlayer::GetNewItemSlot( CItem thisitem ) { UINT tabsize = 30; UINT itemtab = 0; switch(thisitem.itemtype) { case 1:case 2:case 3:case 4:case 5:case 6:case 7:case 8:case 9://equip itemtab = 0; break; case 10://consumibles itemtab = 1; break; case 11:case 12://etc itemtab = 2; break; case 14://pat itemtab = 3; break; default: Log(MSG_WARNING,"unknown itemtype %i", thisitem.itemtype); return 0xffff; break; } //useitems and natural //first we try to find a slot that already contains some of this item //this way the items will always stack if possible. if(itemtab == 1 || itemtab == 2) { for(int i=0;i<30;i++) { UINT slot=12; slot += (tabsize*itemtab)+i; if(items[slot].itemnum == thisitem.itemnum && items[slot].itemtype == thisitem.itemtype) { int totcount = thisitem.count + items[slot].count; if(totcount < 1000) return slot; } } } //now scan again to find a fully empty slot for mats, useitems and equipable stuff //doesn't matter what tab type for(int i=0;i<30;i++) { UINT slot=12; slot += (tabsize*itemtab)+i; if(items[slot].itemnum==0 &items[slot].count<1) return slot; } return 0xffff; } //count storage items unsigned int CPlayer::Getnstorageitems( CPlayer* thisclient ) { UINT count = 0; for(UINT i=0;i<160;i++) { if(thisclient->storageitems[i].count > 0) count++; } return count; } // Returns a free slot in the storage (0xffff if is full) UINT CPlayer::GetNewStorageItemSlot( CItem thisitem ) { //first check for a slot that already contains this item if it is stackable if(thisitem.itemtype == 10 || thisitem.itemtype == 11 || thisitem.itemtype == 12) { for(UINT i=0;i<144;i++) { if(storageitems[i].itemtype == thisitem.itemtype && storageitems[i].itemnum == thisitem.itemnum) { //now we make sure that the total of the new items plus the ones already there do not exceed 999 int totalcount = storageitems[i].count + thisitem.count; if(totalcount < 1000) { return i; } } } } //so we couldn't find a matching entry to stack onto //or the item is unstackable //Let's look for an empty slot instead then for(UINT i=0;i<144;i++) { if(storageitems[i].itemtype == 0) { return i; } } return 0xffff; } // Erase a object from the user bool CPlayer::ClearObject( unsigned int otherclientid ) { BEGINPACKET( pak, 0x794 ); ADDWORD( pak, otherclientid ); client->SendPacket( &pak ); return true; } // Clean the player values void CPlayer::RestartPlayerVal( ) { ClearBattle( Battle ); Shop->open = false; Trade->trade_target = 0; Trade->trade_status = 0; } int CPlayer::GetQuestVar(short nVarType, short nVarNO){ switch(nVarType){ case 0: { SQuest* activeQuest = GetActiveQuest(); if(activeQuest == NULL) return -1; return activeQuest->Variables[nVarNO]; } case 0x100: { SQuest* activeQuest = GetActiveQuest(); if(activeQuest == NULL) return -1; return activeQuest->GetSwitchBit(nVarNO); } case 0x200://Remaining time Log(MSG_DEBUG, "GetQuestVar got remaining quest time"); return 1; case 0x300: if(nVarNO >= 5) return -1; return quest.EpisodeVar[nVarNO]; case 0x400: if(nVarNO >= 3) return -1; return quest.JobVar[nVarNO]; case 0x500: if(nVarNO >= 7) return -1; return quest.PlanetVar[nVarNO]; case 0x600: if(nVarNO >= 10) return -1; return quest.UnionVar[nVarNO]; default: break; } return -1; } void CPlayer::SetQuestVar(short nVarType, short nVarNO, short nValue){ switch(nVarType){ case 0: { SQuest* activeQuest = GetActiveQuest(); if(activeQuest == NULL) return; activeQuest->Variables[nVarNO] = nValue; } return; case 0x100: { SQuest* activeQuest = GetActiveQuest(); if(activeQuest == NULL) return; activeQuest->SetSwitchBit(nVarNO, nValue); } return; case 0x300: if(nVarNO >= 5) return; quest.EpisodeVar[nVarNO] = nValue; return; case 0x400: if(nVarNO >= 3) return; quest.JobVar[nVarNO] = nValue; return; case 0x500: if(nVarNO >= 7) return; quest.PlanetVar[nVarNO] = nValue; return; case 0x600: if(nVarNO >= 10) return; quest.UnionVar[nVarNO] = nValue; return; default: break; } } int CPlayer::ExecuteQuestTrigger(dword hash) { //Code that actually works. Taken from KTRose CQuestTrigger* trigger = NULL; CQuestTrigger* nexttrigger = NULL; bool logme = false; if (this->questdebug) logme = true; CheckQuest = -1; //if (GServer->questdebug) if (this->questdebug) Log (MSG_QUESTDEBUG, "ExecuteQuestTrigger:: searching for trigger %i in TriggerList with size %i", hash, GServer->TriggerList.size ()); for (unsigned j = 0; j < GServer->TriggerList.size (); j++) { if (GServer->TriggerList.at (j)->TriggerHash == hash) { trigger = GServer->TriggerList.at (j); nexttrigger = GServer->TriggerList.at (j + 1); break; } } if (trigger == NULL) { if (this->questdebug) Log (MSG_QUESTDEBUG, "ExecuteQuestTrigger:: Could not find quest trigger. Returning Failure"); return QUEST_FAILURE; } int success = QUEST_SUCCESS; if (this->questdebug) Log (MSG_QUESTDEBUG, "ExecuteQuestTrigger:: Trigger executed %s[%i]", trigger->TriggerName, trigger->CheckNext); for (dword i = 0; i < trigger->ConditionCount; i++) { int command = trigger->Conditions[i]->opcode; if (command > 30 || command < 0) continue; success = (*GServer->qstCondFunc[command])(GServer, this, trigger->Conditions[i]->data); if (this->questdebug) Log (MSG_QUESTDEBUG, "ExecuteQuestTrigger:: Condition %03u returned %d", command, success); if (success == QUEST_FAILURE) { if (!trigger->CheckNext) return success; else return ExecuteQuestTrigger (nexttrigger->TriggerHash); } } for (dword i = 0; i < trigger->ActionCount; i++) { int command = trigger->Actions[i]->opcode; if (this->questdebug) Log (MSG_QUESTDEBUG, "ExecuteQuestTrigger:: command %03u", command); if (command > 35 || command < 0) continue; /*if (this->questdebug) Log(MSG_QUESTDEBUG, "ExecuteQuestTrigger:: Still good after command value check");*/ success = (*GServer->qstRewdFunc[command])(GServer, this, trigger->Actions[i]->data); if (this->questdebug) Log (MSG_QUESTDEBUG, "ExecuteQuestTrigger:: reward %03u returned %d", command, success); } return success; //CQuestTrigger* trigger = NULL; // CQuestTrigger* nexttrigger = NULL; // CheckQuest = -1; // for(unsigned j=0; j < GServer->TriggerList.size(); j++) // { // if (GServer->TriggerList.at(j)->TriggerHash == hash) // { // trigger = GServer->TriggerList.at(j); // nexttrigger = GServer->TriggerList.at(j + 1); // break; // } // } // if (trigger == NULL) return QUEST_FAILURE; // int success = QUEST_SUCCESS; // Log(MSG_DEBUG, "Trigger Executed: %s [%i] hash %i", trigger->TriggerName, trigger->CheckNext, hash); // if(Session->codedebug)GServer->SendPM(this, "Trigger executed %s[%i]", trigger->TriggerName, trigger->CheckNext); // for (dword i = 0; i < trigger->ConditionCount; i++) // { // int command = trigger->Conditions[i]->opcode; // if (command > 30 || command < 0) continue; // success = (*GServer->qstCondFunc[command])(GServer, this, trigger->Conditions[i]->data); // //Log(MSG_DEBUG, "Condition %03u returned %d", command, success); // if(Session->codedebug)GServer->SendPM(this, "Condition %03u returned %d", command, success); // if (success == QUEST_FAILURE) // { // if (!trigger->CheckNext) // return success; // else return ExecuteQuestTrigger(nexttrigger->TriggerHash); // } // } // for (dword i = 0; i < trigger->ActionCount; i++) // { // int command = trigger->Actions[i]->opcode; // if(Session->codedebug)GServer->SendPM(this, "command %03u", command); // if (command > 30 || command < 0) continue; // if(Session->codedebug)GServer->SendPM(this, "Still good after command value check"); // success = (*GServer->qstRewdFunc[command])(GServer, this, trigger->Actions[i]->data); // if(Session->codedebug)GServer->SendPM(this, "reward %03u returned %d", command, success); // //Log(MSG_DEBUG, "Reward %03u returned %d", command, success); // } // return success; } // 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( ); //if(stance = SITTING) //{ // hpamount = hpamount * 4; // mpamount = mpamount * 4 //} 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; } // Heal Player when use Food/Pots bool CPlayer::PlayerHeal() { clock_t transtime = clock() - UsedItem->lastRegTime; if( UsedItem->usevalue != 0 && transtime >= 0.3 * CLOCKS_PER_SEC ) { if( UsedItem->used < UsedItem->usevalue && Stats->HP > 0 ) { int value = UsedItem->userate; if((UsedItem->usevalue - UsedItem->used) < value) { value = UsedItem->usevalue - UsedItem->used; } switch( UsedItem->usetype ) { case 16: // HP Stats->HP += value; if(Stats->HP > Stats->MaxHP) Stats->HP = Stats->MaxHP; break; case 17: // MP Stats->MP += value; if(Stats->MP > Stats->MaxMP) Stats->MP = Stats->MaxMP; break; case 37: // Skill points CharInfo->SkillPoints += value; break; case 76: //Stamina CharInfo->stamina += value; if(CharInfo->stamina > 5000) CharInfo->stamina = 5000; break; default: break; } UsedItem->used += value; UsedItem->lastRegTime = clock(); } else { BEGINPACKET( pak,0x7b7 ); ADDWORD ( pak, clientid ); ADDDWORD ( pak, GServer->BuildBuffs( this ) ); switch( UsedItem->usetype ) { case 16: // HP ADDWORD( pak, Stats->HP ); break; case 17: // MP ADDWORD( pak, Stats->MP ); break; case 37: //Skill Points ADDWORD( pak, CharInfo->SkillPoints ); break; case 76: //Stamina ADDWORD( pak, CharInfo->stamina ); break; default: break; } GServer->SendToVisible( &pak, this ); UsedItem->used = 0; UsedItem->usevalue = 0; UsedItem->userate = 0; UsedItem->usetype = 0; } BEGINPACKET( pak, 0x7ec ); ADDWORD( pak, Stats->HP); ADDWORD( pak, Stats->MP ); client->SendPacket( &pak ); } return true; } void CPlayer::ReduceABC( ) { unsigned int weapontype = 0; weapontype = GServer->EquipList[WEAPON].Index[items[7].itemnum]->type; switch(weapontype) { case 231: items[132].count--; if(items[132].count<=0) { ClearBattle( Battle ); ClearItem( items[132] ); } break; case 232: items[133].count--; if(items[133].count<=0) { ClearBattle( Battle ); ClearItem( items[133] ); } break; case 233: items[134].count--; if(items[134].count<=0) { ClearBattle( Battle ); ClearItem( items[134] ); } break; case 271: items[132].count--; if(items[132].count<=0) { ClearBattle( Battle ); ClearItem( items[135] ); } break; default: break; } } SQuest* CPlayer::GetActiveQuest( ) { for(dword i = 0; i < 10; i++){ if(quest.quests[i].QuestID != ActiveQuest) continue; return &quest.quests[i]; } return NULL; } // return party pointer CParty* CPlayer::GetParty( ) { return Party->party; } CLAN* CPlayer::GetClan( ) { return Clan; } // return intelligence unsigned int CPlayer::GetInt( ) { return Attr->Int + Attr->Eint; } // add item [return item slot [0xffff if couldn't add it]] unsigned int CPlayer::AddItem( CItem item ) { unsigned int newslot = 0; newslot = GetNewItemSlot( item ); if(newslot != 0xffff) { if(items[newslot].count > 0) { unsigned int ntcount = item.count; unsigned int utcount = items[newslot].count; if(ntcount + utcount > 999) { item.count = ntcount + utcount - 999; items[newslot].count = 999; unsigned int otherslot = GetNewItemSlot( item ); if(otherslot != 0xffff) { if(items[otherslot].count != 0) items[otherslot].count += item.count; else items[otherslot] = item; return newslot * 1000 + otherslot; } else { items[newslot].count = utcount; return 0xffff; //not inventory space } } else items[newslot].count = ntcount + utcount; } else items[newslot] = item; } return newslot; } 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::takeSkillCost( CSkills* skill) { for (int i = 0; i < 2; i++) { if (skill->costtype[i] == 0) continue; Log(MSG_INFO, "Skill cost: %i", skill->costamount[i]); switch (skill->costtype[i]) { case sHP: Stats->HP -= skill->costamount[i]; break; case sMP: Stats->MP -= (skill->costamount[i] - (skill->costamount[i] * Stats->MPReduction / 100)); Log(MSG_INFO, "MP: %i", Stats->MP); break; case sMoney: CharInfo->Zulies -= skill->costamount[i]; break; case sStamina: CharInfo->stamina -= skill->costamount[i]; break; case sCartGauge: Log(MSG_INFO, "Couldn't take CartGauge, no variable"); break; default: break; } } }