Combat.cpp
上传用户:jxpjxmjjw
上传日期:2009-12-07
资源大小:5877k
文件大小:20k
源码类别:

模拟服务器

开发平台:

Visual C++

  1. // Copyright (C) 2004 Team Python //   // 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "Combat.h" #include "NetworkInterface.h" #include "Log.h" #include "GameClient.h" #include "Opcodes.h" #include "Character.h" #include "WorldServer.h" #include "UpdateMask.h" #include "Stats.h" #include "math.h" #define world WorldServer::getSingleton() void CombatHandler::HandleMsg( wowWData & recv_data, GameClient *pClient ) {     wowWData data;     char f[256];     sprintf(f, "WORLD: Combat Opcode 0x%.4X from %u", recv_data.opcode, pClient->getCurrentChar()->getGUID());     Log::getSingleton( ).outString( f );     switch (recv_data.opcode)     {         case CMSG_ATTACKSWING:     {             uint32 mguid[2], pguid;     pguid = pClient->getCurrentChar()->getGUID();             recv_data >> mguid[0] >> mguid[1];     // AttackSwing             Log::getSingleton( ).outString( "WORLD: Recvd CMSG_ATTACKSWING Message" );             Unit *pEnemy;             if(world.mCreatures.find(mguid[0]) == world.mCreatures.end() ||                 ((pEnemy = world.mCreatures[mguid[0]])->getGUIDHigh() != mguid[1]))             {                 Log::getSingleton( ).outString( "WORLD: Can't attack character" );                 break; // we do not attack PCs for now             }             pClient->getCurrentChar()->addStateFlag(UF_ATTACKING);             pClient->getCurrentChar()->setCombat(true);             smsg_AttackStart(pClient->getCurrentChar(), pEnemy);         }break;     case CMSG_ATTACKSTOP:     {     uint32 mguid[2];             mguid[0] = *(pClient->getCurrentChar()->getSelectionPtr());             mguid[1] = *(pClient->getCurrentChar()->getSelectionPtr()+1);             smsg_AttackStop((Unit*)pClient->getCurrentChar(), mguid);             pClient->getCurrentChar()->setCombat(false);             pClient->getCurrentChar()->clearStateFlag(UF_ATTACKING); //            pClient->getCurrentChar()->removeUnitFlag(0x00080000);     }break;     } } //================================================================================================ //  AttackerStateUpdate //  This function determines whether there is a hit, and the resultant damage //================================================================================================ void CombatHandler::AttackerStateUpdate(Unit *pAttacker, Unit *pVictim, int32 damage) {     if (pVictim->getUpdateValue(UNIT_FIELD_HEALTH) == 0 ||          pAttacker->getUpdateValue(UNIT_FIELD_HEALTH) == 0 )          return; pVictim->setCombat(true); pAttacker->setCombat(true);     wowWData data; uint32 absorb = 0; uint32 shield = 0; uint32 mana_dmg = 0;
  2. uint32 critiq = 0;     uint32 hit_status = 0xe2; if(damage == 0)
  3. { damage = CalculateDamage(pAttacker); // weaker attack for mobs lvl+ player if (pAttacker->getUpdateValue(PLAYER_NEXT_LEVEL_XP) != NULL && damage) { //printf("Ataque do PLAYER %u - Dmg: %un", pAttacker->getGUID() ,damage); int lvl_diff = (pVictim->getUpdateValue(UNIT_FIELD_LEVEL) - pAttacker->getUpdateValue(UNIT_FIELD_LEVEL)); if (lvl_diff == 1) { damage -= 2; } else if (lvl_diff == 2) {         damage = damage/2; } else if (lvl_diff >=2) { damage = rand()%3; } // set player as mob 'owner' uint32 hp = pVictim->getUpdateValue(UNIT_FIELD_HEALTH); uint32 maxhp = pVictim->getUpdateValue(UNIT_FIELD_MAXHEALTH); if ((hp < maxhp*.8) && (hp > maxhp*.5)) pVictim->setkillerGUID(pAttacker->getGUID()); // printf("nnuhuuuuu!!! attackerGUID: %unn", pAttacker->getGUID()); // if (health < 80%) && (health > 50%)  // setkillerGUID(uint32 guid) } if (damage < 0) { damage = 0; } //printf("Damage changed to %un", damage); }// get absorb/shield stuff
  4. if(pAttacker->getGUIDHigh() == 0 ) //if player
  5. {
  6. uint8 agi = pAttacker->getUpdateValue(UNIT_FIELD_STAT1);
  7. // if( rand()%(agi) > (rand()%pAttacker->getLevel()+agi/2) ) critiq = pAttacker->getLevel()/2+1;
  8. if ((agi) && ( rand()%(agi) > (rand()%pAttacker->getLevel()+agi/2))) damage *= 1.5;
  9. // printf("Critical changed to %un", critiq);
  10. } if(pVictim->m_absorb == 1)
  11. {
  12. //printf("ok we will absorb some dmgn"); SpellInformation spellInfo; DatabaseInterface *dbi = Database::getSingleton().createDatabaseInterface(); //get a hook for the DB spellInfo = dbi->GetSpellInformation ( pVictim->m_absorbspell ); //returns a SpellInformation object/struct absorb = spellInfo.DmgPlus1; Database::getSingleton().removeDatabaseInterface( dbi ); //clean up used resources } if(pVictim->m_shield == 1)
  13. { //printf("ok we will shield some dmgn"); SpellInformation spellInfo; DatabaseInterface *dbi = Database::getSingleton().createDatabaseInterface(); //get a hook for the DB spellInfo = dbi->GetSpellInformation ( pVictim->m_shieldspell ); //returns a SpellInformation object/struct shield = spellInfo.DmgPlus1; Database::getSingleton().removeDatabaseInterface( dbi ); //clean up used resources }
  14. //START OF LINA
  15. if(pVictim->getUpdateValue(UNIT_FIELD_RESISTANCES)>0)
  16. {
  17. uint32 armor=pVictim->getUpdateValue(UNIT_FIELD_RESISTANCES);
  18. absorb += armor;
  19. }
  20. //END OF LINA
  21. // absorb damage if damage absorb is activated
  22. int32 absorbed=0;
  23. if( absorb > 0 )
  24. {
  25. //absorbed = (uint32)((float)damage/float(100)*(float(100)-(float)absorb));
  26. absorbed = (uint32)damage-absorb*absorb/2000;
  27. if(absorbed < 0) //if armor absorbe all damage
  28. {
  29. absorb = damage-1; //absorb all - 1
  30. absorbed = 1; //set receive damage to 1
  31. }
  32. else 
  33. {
  34. absorb = damage-absorbed; //set absorb to the correct value
  35. }
  36. }
  37. else //if no armor
  38. {
  39. absorbed=damage; //give full damage to user 
  40. }
  41. /* // absorb damage if damage absorb is activated uint32 absorbed = (float)damage/float(100)*(float(100)-(float)absorb); absorb = absorbed-damage; if(absorbed > damage) absorbed = 1; if(absorb < 0) absorb = 0;
  42. */ // use mana shield if activated if(pVictim->m_shield)
  43. { uint32 mana = pVictim->getUpdateValue(UNIT_FIELD_POWER1); if(mana < shield) shield = pVictim->getUpdateValue(UNIT_FIELD_POWER1);
  44. if(absorbed-shield > absorbed)
  45. {// happens if shield is bigger then absorbed and that would make a char unplayable mana_dmg = absorbed-1; absorbed = 1; absorb = mana_dmg; //printf("#1 mana_dmg is %u and absorbed is %un", mana_dmg,absorbed); }
  46. else
  47. { absorbed = absorbed-shield; mana_dmg = shield; absorb = mana_dmg; //printf("#2 mana_dmg is %u and absorbed is %un", mana_dmg,absorbed); } pVictim->setUpdateValue(UNIT_FIELD_POWER1,mana-mana_dmg);// if mana_dmg is >0 then absorb it or leave it as it is } /*     uint32 some_value = 0xffffffff;     some_value = 0x0; */     data.clear();     data.Initialise(61, SMSG_ATTACKERSTATEUPDATE);     data.writeData( hit_status );   // Attack flags     data.writeData( pAttacker->getGUID() );     data.writeData( pAttacker->getGUIDHigh() );     data.writeData( pVictim->getGUID() );     data.writeData( pVictim->getGUIDHigh() );     data.writeData( absorbed ); // damage     data.writeData( uint8(1) );     // Damage type counter     // for each...     data.writeData( uint32(0) );    // Damage type, // 0 - white font, 1 - yellow     data.writeData( uint32(0x0) );  // damage float     data.writeData( damage );       // Damage amount damage     data.writeData( absorb ); // damage absorbed     data.writeData( uint32(1) );    // new victim state     data.writeData( uint32(0) );    // victim round duration     data.writeData( uint32(0) );    // additional spell damage amount     data.writeData( uint32(0) );    // additional spell damage id     data.writeData( shield );    // Damage amount blocked     pAttacker->SendMessageToSet(&data, true);     //printf("AttackerStateUpdate:  %u attacked %u for %u dmg-%u absorb=%u absorbed (shield %u).n", pAttacker->getGUID(), pVictim->getGUID(), damage, absorb, absorbed, shield);
  48.     DealDamage(pAttacker, pVictim, absorbed); } void CombatHandler::smsg_AttackStop(Unit* pAttacker, uint32 victim_guid[2]) { uint32 attacker_guid[2]; attacker_guid[0] = pAttacker->getGUID(); attacker_guid[1] = pAttacker->getGUIDHigh(); wowWData data;     data.Initialise( 20, SMSG_ATTACKSTOP );     data << attacker_guid[0] << attacker_guid[1] << victim_guid[0] << victim_guid[1] << uint32( 0 ); //    world.SendUnitAreaMessage(&data, pAttacker);     pAttacker->SendMessageToSet(&data, true);     printf("%u stopped attacking %un", attacker_guid[0], victim_guid[0]); // Changed by nothin if(pAttacker->getUpdateValue(UNIT_FIELD_SUMMONEDBY) != 0)
  49. { pAttacker->m_creatureState = STOPPED; } } void CombatHandler::smsg_AttackStart(Unit* pAttacker, Unit* pVictim) { //check if victim is close to attacker float dx, dy, dz, length, reach, radius; dx = pVictim->getPositionX() - pAttacker->getPositionX();     dy = pVictim->getPositionY() - pAttacker->getPositionY();     dz = pVictim->getPositionZ() - pAttacker->getPositionZ(); length = sqrt((dx*dx) + (dy*dy) + (dz*dz)); //distance between you and mob radius = pVictim->getUpdateFloatValue(UNIT_FIELD_BOUNDINGRADIUS); reach = pAttacker->getUpdateFloatValue(UNIT_FIELD_COMBATREACH); if (length < reach + radius) { // Prevent user from ignoring attack speed and stopping and start combat really really fast     if (pAttacker->isAttackReady())     {         AttackerStateUpdate(pAttacker, pVictim, 0);         pAttacker->setAttackTimer();     }     // Send out ATTACKSTART     wowWData data;     data.clear();     data.Initialise( 16, SMSG_ATTACKSTART );     data << pAttacker->getGUID() << pAttacker->getGUIDHigh() << pVictim->getGUID() << pVictim->getGUIDHigh(); //    world.SendUnitAreaMessage(&data, pAttacker);  //probably global     pAttacker->SendMessageToSet(&data, true);     Log::getSingleton( ).outString( "WORLD: Sent SMSG_ATTACKSTART" ); } else { pAttacker->clearStateFlag(UF_ATTACKING); pAttacker->setCombat(false); pVictim->setCombat(false); } // FLAGS changed so other players see attack animation //    pAttacker->addUnitFlag(0x00080000); //    pAttacker->setUpdateMaskBit(UNIT_FIELD_FLAGS ); } void CombatHandler::DealDamage(Unit *pAttacker, Unit *pVictim, uint32 damage) {
  50. Unit * pPetMaster;
  51.     uint32 health = pVictim->getUpdateValue(UNIT_FIELD_HEALTH ); pAttacker->setCombat(true);
  52. pVictim->setCombat(true);     if (health <= damage)     { // printf("ok now he is deadn"); pVictim->generateLoot();         // victim died!         pVictim->setDeathState(JUST_DIED);         // Send SMSG_PARTYKILLLOG 0x1e6         // To everyone in the party?         // SMSG_ATTACKSTOP         uint32 aguid[2], vguid[2];         aguid[0] = pAttacker->getGUID();         aguid[1] = pAttacker->getGUIDHigh();         vguid[0] = pVictim->getGUID();         vguid[1] = pVictim->getGUIDHigh();         smsg_AttackStop(pVictim, aguid);         // Send MSG_MOVE_ROOT   0xe7 // if player, dismount if (pVictim->isPlayer()) { wowWData data; pVictim->setUpdateValue(UNIT_FIELD_MOUNTDISPLAYID , 0); pVictim->removeUnitFlag( 0x003000 ); float dmspeed = 7.5; // Exact value of normal player speed data.Initialise( 12, SMSG_FORCE_SPEED_CHANGE );         data << pVictim->getUpdateValue( OBJECT_FIELD_GUID ); data << pVictim->getUpdateValue( OBJECT_FIELD_GUID + 1 );     data << dmspeed;         pVictim->SendMessageToSet( &data, true ); }         // Set update values... try flags 917504         // health         pVictim->setUpdateValue(UNIT_FIELD_HEALTH, 0); //        pVictim->setUpdateValue(UNIT_FIELD_POWER1, 0);         // then another update message, sets health to 0, maxhealth to 100, and dynamic flags         pVictim->setUpdateMaskBit(UNIT_FIELD_MAXHEALTH); // pVictim->setUpdateMaskBit(UNIT_FIELD_MAXPOWER1);         pVictim->removeUnitFlag(0x00080000);         if ( !pVictim->isPlayer() ) pVictim->setUpdateValue(UNIT_DYNAMIC_FLAGS, 1);         
  53. //LINA
  54. if( pAttacker->isPet() ) //if pet kill someone, give xp to summoner
  55. {
  56. printf("It's a PET, master %u!n", pAttacker->getUpdateValue(UNIT_FIELD_SUMMONEDBY) );
  57. pPetMaster = world.GetCharacter( pAttacker->getUpdateValue(UNIT_FIELD_SUMMONEDBY) );
  58. if(!pPetMaster) 
  59. {
  60. pPetMaster=pAttacker;
  61. }
  62. smsg_AttackStop(pAttacker, vguid);
  63.             pAttacker->removeUnitFlag(0x00080000);
  64.             pAttacker->setUpdateMaskBit(UNIT_FIELD_FLAGS );
  65.             pAttacker->addStateFlag(UF_TARGET_DIED);
  66. }
  67. else
  68. pPetMaster=pAttacker;
  69. uint32 killerGUID = pVictim->getkillerGUID();
  70. if ((killerGUID != pPetMaster->getGUID()) && killerGUID) {
  71. //printf("Roubo de XP!! Quem ganha eh: %u, nao %u!n",  killerGUID, pPetMaster->getGUID());
  72. WorldServer::ClientSet::iterator itr; for (itr = world.mClients.begin(); itr != world.mClients.end(); itr++) { if (((GameClient*)(*itr))->IsInWorld()) { if (((GameClient*)(*itr))->getCurrentChar()->getGUID() == killerGUID) pPetMaster = ((GameClient*)(*itr))->getCurrentChar(); continue; } } }
  73.         if (pPetMaster->isPlayer())
  74. {             uint32 xp = CalculateXpToGive(pVictim, pPetMaster);             // check running quests in case this monster belongs to it             uint32 entry = 0;             if (!pVictim->isPlayer())                 entry = pVictim->getUpdateValue(OBJECT_FIELD_ENTRY );             // Is this player part of a group? new by LeMMiNGS: only share xp with near party members, also no xp steal by group invite if (((Character*)pPetMaster)->IsInGroup()) { Group *pGroup = world.GetGroupByLeader(((Character*)pPetMaster)->GetGroupLeader()); uint32 higherlvl=pPetMaster->getLevel(), num=0;                 for (uint32 c=0; c < pGroup->count; c++){                     Character *pGroupGuy = world.mCharacters[pGroup->members[c].guid]; if ( (world.CalcDistance( (Unit *)pPetMaster, (Unit *)pGroupGuy) < UPDATE_DISTANCE) &&  (pPetMaster->getMapId() == (pGroupGuy->getMapId()))) { if (pGroupGuy->getLevel()>higherlvl) { higherlvl = pGroupGuy->getLevel();             xp = CalculateXpToGive(pVictim, pGroupGuy); } num++; } }                 //xp /= pGroup->count;                 xp /= num; if (num >1)   xp *= 1.2;                 for (uint32 c=0; c < pGroup->count; c++){                     Character *pGroupGuy = world.mCharacters[pGroup->members[c].guid]; if ( (world.CalcDistance( (Unit *)pPetMaster, (Unit *)pGroupGuy) < UPDATE_DISTANCE) &&  (pPetMaster->getMapId() == (pGroupGuy->getMapId()  ))) {                     pGroupGuy->giveXP(xp, pVictim->getGUID(), pVictim->getGUIDHigh()); } if (!pVictim->isPlayer())                         pGroupGuy->KilledMonster(entry, pVictim->getGUID()); pGroupGuy->setCombat(false);
  75. }             }             else             {                 // update experience                 ((Character*)pPetMaster)->giveXP(xp, pVictim->getGUID(), pVictim->getGUIDHigh());                 if (!pVictim->isPlayer())                     ((Character*)pPetMaster)->KilledMonster(entry, pVictim->getGUID()); pPetMaster->setCombat(false);             }         }         else         {             smsg_AttackStop(pAttacker, vguid);             pAttacker->removeUnitFlag(0x00080000);             pAttacker->setUpdateMaskBit(UNIT_FIELD_FLAGS );             pAttacker->addStateFlag(UF_TARGET_DIED);
  76. //LINA
  77. if( pVictim->isPet() )//if npc kill a pet, attack summoner
  78. {
  79. pPetMaster = world.GetCharacter( pVictim->getUpdateValue(UNIT_FIELD_SUMMONEDBY) );
  80. if(pPetMaster) 
  81. {
  82. pAttacker->AI_ChangeState(ATTACKING); // when attacked mobs stop moving around
  83. pAttacker->AI_AttackReaction(pPetMaster, damage);
  84. }
  85. }         }     } 
  86. else 
  87. {         pVictim->setUpdateValue(UNIT_FIELD_HEALTH , health - damage); // <WoW Chile Dev Team> Start Change // this need alot of work. ///////////////// PET ATTACK THE ONE WHO ATTACKS ITS MASTER by nothin///////// if(pVictim->isPlayer())
  88. { if(pVictim->getUpdateValue(UNIT_FIELD_SUMMON) != 0)
  89. { petGUID = pVictim->getUpdateValue(UNIT_FIELD_SUMMON);
  90. Unit * pPet=world.GetCreature(petGUID);
  91. if(pPet)
  92. { if(pPet->m_pet_state != 0)
  93. {
  94. pPet->AI_ChangeState(ATTACKING); pPet->AI_AttackReaction(pAttacker, damage); }
  95. } } } /////////////////////////////////////////////////////////////////////////////         else { pVictim->AI_ChangeState(ATTACKING); // when attacked mobs stop moving around pVictim->AI_AttackReaction(pAttacker, damage); /* //uint32 max_health = getUpdateValue(UNIT_FIELD_MAXHEALTH); //uint32 health_porcent = (max_health*10)/100; // this if for know 10% of total healt,need changes about mobs lvls pVictim->AI_ChangeState(3); //if mob are attack then they stop moving around             pVictim->AI_AttackReaction(pAttacker, damage); //well mobs scape if have a movement assignet atm //if(health<=health_porcent) {} */ } // <WoW Chile Dev Team> Start Change     } } /* void CombatHandler::Heal(Unit *pAttacker, Unit *pVictim, uint32 damage) {     uint32 health = pVictim->getUpdateValue(UNIT_FIELD_HEALTH );     if (health <= damage)     { pVictim->generateLoot();         // victim died!         pVictim->setDeathState(JUST_DIED);         // Send SMSG_PARTYKILLLOG 0x1e6         // To everyone in the party?         // SMSG_ATTACKSTOP         uint32 aguid[2], vguid[2];         aguid[0] = pAttacker->getGUID();         aguid[1] = pAttacker->getGUIDHigh();         vguid[0] = pVictim->getGUID();         vguid[1] = pVictim->getGUIDHigh();         smsg_AttackStop(pVictim, aguid);         // Send MSG_MOVE_ROOT   0xe7         // Set update values... try flags 917504         // health         pVictim->setUpdateValue(UNIT_FIELD_HEALTH, 0);         // then another update message, sets health to 0, maxhealth to 100, and dynamic flags         pVictim->setUpdateValue(UNIT_FIELD_HEALTH, 0);         pVictim->setUpdateMaskBit(UNIT_FIELD_MAXHEALTH);         pVictim->removeUnitFlag(0x00080000);         if (!pVictim->isPlayer()) pVictim->setUpdateValue(UNIT_DYNAMIC_FLAGS, 1);         if (pAttacker->isPlayer()){             uint32 xp = CalculateXpToGive(pVictim, pAttacker);             // check running quests in case this monster belongs to it             uint32 entry = pVictim->getUpdateValue(OBJECT_FIELD_ENTRY );             // Is this player part of a group?             Group *pGroup = WorldServer::getSingleton().GetGroupByLeader(((Character*)pAttacker)->GetGroupLeader());             if (pGroup){                 xp /= pGroup->count;                 for (uint32 c=0; c < pGroup->count; c++){                     Character *pGroupGuy = world.mCharacters[pGroup->members[c].guid];                     pGroupGuy->giveXP(xp, pVictim->getGUID(), pVictim->getGUIDHigh());                     pGroupGuy->KilledMonster(entry, pVictim->getGUID());                 }             }             else             {                 // update experience                 ((Character*)pAttacker)->giveXP(xp, pVictim->getGUID(), pVictim->getGUIDHigh());                 ((Character*)pAttacker)->KilledMonster(entry, pVictim->getGUID());             }         }         else         {             smsg_AttackStop(pAttacker, vguid);             pAttacker->removeUnitFlag(0x00080000);             pAttacker->setUpdateMaskBit(UNIT_FIELD_FLAGS );             pAttacker->addStateFlag(UF_TARGET_DIED);         }     } else {         pVictim->setUpdateValue(UNIT_FIELD_HEALTH , health + damage);     } }
  96. */