Share Pastebin
Guest
Public paste!

Untitled

By: a guest | Feb 9th, 2010 | Syntax: None | Size: 18.19 KB | Hits: 32 | Expires: Never
Copy text to clipboard
  1. /*
  2.  * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
  3.  *
  4.  * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19.  */
  20.  
  21. #include "Common.h"
  22. #include "WorldPacket.h"
  23. #include "Log.h"
  24. #include "Corpse.h"
  25. #include "GameObject.h"
  26. #include "Player.h"
  27. #include "ObjectAccessor.h"
  28. #include "WorldSession.h"
  29. #include "LootMgr.h"
  30. #include "Object.h"
  31. #include "Group.h"
  32. #include "World.h"
  33. #include "Util.h"
  34.  
  35. void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data )
  36. {
  37.     sLog.outDebug("WORLD: CMSG_AUTOSTORE_LOOT_ITEM");
  38.     Player  *player =   GetPlayer();
  39.     uint64   lguid =    player->GetLootGUID();
  40.     Loot    *loot;
  41.     uint8    lootSlot;
  42.  
  43.     recv_data >> lootSlot;
  44.  
  45.     if (IS_GAMEOBJECT_GUID(lguid))
  46.     {
  47.         GameObject *go = player->GetMap()->GetGameObject(lguid);
  48.  
  49.         // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
  50.         if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player,INTERACTION_DISTANCE)))
  51.         {
  52.             player->SendLootRelease(lguid);
  53.             return;
  54.         }
  55.  
  56.         loot = &go->loot;
  57.     }
  58.     else if (IS_ITEM_GUID(lguid))
  59.     {
  60.         Item *pItem = player->GetItemByGuid( lguid );
  61.  
  62.         if (!pItem)
  63.         {
  64.             player->SendLootRelease(lguid);
  65.             return;
  66.         }
  67.  
  68.         loot = &pItem->loot;
  69.     }
  70.     else if (IS_CORPSE_GUID(lguid))
  71.     {
  72.         Corpse *bones = ObjectAccessor::GetCorpse(*player, lguid);
  73.         if (!bones)
  74.         {
  75.             player->SendLootRelease(lguid);
  76.             return;
  77.         }
  78.         loot = &bones->loot;
  79.     }
  80.     else
  81.     {
  82.         Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid);
  83.  
  84.         bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed);
  85.  
  86.         if( !ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE) )
  87.         {
  88.             player->SendLootRelease(lguid);
  89.             return;
  90.         }
  91.  
  92.         loot = &pCreature->loot;
  93.     }
  94.  
  95.     QuestItem *qitem = NULL;
  96.     QuestItem *ffaitem = NULL;
  97.     QuestItem *conditem = NULL;
  98.  
  99.     LootItem *item = loot->LootItemInSlot(lootSlot,player,&qitem,&ffaitem,&conditem);
  100.  
  101.     if(!item)
  102.     {
  103.         player->SendEquipError( EQUIP_ERR_ALREADY_LOOTED, NULL, NULL );
  104.         return;
  105.     }
  106.  
  107.     // questitems use the blocked field for other purposes
  108.     if (!qitem && item->is_blocked)
  109.     {
  110.         player->SendLootRelease(lguid);
  111.         return;
  112.     }
  113.  
  114.     ItemPosCountVec dest;
  115.     uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item->itemid, item->count );
  116.     if ( msg == EQUIP_ERR_OK )
  117.     {
  118.         Item * newitem = player->StoreNewItem( dest, item->itemid, true, item->randomPropertyId);
  119.  
  120.         if (qitem)
  121.         {
  122.             qitem->is_looted = true;
  123.             //freeforall is 1 if everyone's supposed to get the quest item.
  124.             if (item->freeforall || loot->GetPlayerQuestItems().size() == 1)
  125.                 player->SendNotifyLootItemRemoved(lootSlot);
  126.             else
  127.                 loot->NotifyQuestItemRemoved(qitem->index);
  128.         }
  129.         else
  130.         {
  131.             if (ffaitem)
  132.             {
  133.                 //freeforall case, notify only one player of the removal
  134.                 ffaitem->is_looted=true;
  135.                 player->SendNotifyLootItemRemoved(lootSlot);
  136.             }
  137.             else
  138.             {
  139.                 //not freeforall, notify everyone
  140.                 if(conditem)
  141.                     conditem->is_looted=true;
  142.                 loot->NotifyItemRemoved(lootSlot);
  143.             }
  144.         }
  145.  
  146.         //if only one person is supposed to loot the item, then set it to looted
  147.         if (!item->freeforall)
  148.             item->is_looted = true;
  149.  
  150.         --loot->unlootedCount;
  151.  
  152.         player->SendNewItem(newitem, uint32(item->count), false, false, true);
  153.         player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count);
  154.         player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, loot->loot_type, item->count);
  155.     }
  156.     else
  157.         player->SendEquipError( msg, NULL, NULL );
  158. }
  159.  
  160. void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ )
  161. {
  162.     sLog.outDebug("WORLD: CMSG_LOOT_MONEY");
  163.  
  164.     Player *player = GetPlayer();
  165.     uint64 guid = player->GetLootGUID();
  166.     if(!guid)
  167.         return;
  168.  
  169.     Loot *pLoot = NULL;
  170.  
  171.     switch(GUID_HIPART(guid))
  172.     {
  173.         case HIGHGUID_GAMEOBJECT:
  174.         {
  175.             GameObject *pGameObject = GetPlayer()->GetMap()->GetGameObject(guid);
  176.  
  177.             // not check distance for GO in case owned GO (fishing bobber case, for example)
  178.             if (pGameObject && ((pGameObject->GetOwnerGUID()==_player->GetGUID() || pGameObject->IsWithinDistInMap(_player,INTERACTION_DISTANCE))))
  179.                 pLoot = &pGameObject->loot;
  180.  
  181.             break;
  182.         }
  183.         case HIGHGUID_CORPSE:                               // remove insignia ONLY in BG
  184.         {
  185.             Corpse *bones = ObjectAccessor::GetCorpse(*GetPlayer(), guid);
  186.  
  187.             if (bones && bones->IsWithinDistInMap(_player,INTERACTION_DISTANCE) )
  188.                 pLoot = &bones->loot;
  189.  
  190.             break;
  191.         }
  192.         case HIGHGUID_ITEM:
  193.         {
  194.             if(Item *item = GetPlayer()->GetItemByGuid(guid))
  195.                 pLoot = &item->loot;
  196.             break;
  197.         }
  198.         case HIGHGUID_UNIT:
  199.         {
  200.             Creature* pCreature = GetPlayer()->GetMap()->GetCreature(guid);
  201.  
  202.             bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed);
  203.  
  204.             if ( ok_loot && pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE) )
  205.                 pLoot = &pCreature->loot ;
  206.  
  207.             break;
  208.         }
  209.         default:
  210.             return;                                         // unlootable type
  211.     }
  212.  
  213.     if( pLoot )
  214.     {
  215.         if (!IS_ITEM_GUID(guid) && player->GetGroup())      //item can be looted only single player
  216.         {
  217.             Group *group = player->GetGroup();
  218.  
  219.             std::vector<Player*> playersNear;
  220.             for (GroupReference *itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
  221.             {
  222.                 Player* playerGroup = itr->getSource();
  223.                 if(!playerGroup)
  224.                     continue;
  225.                 if (player->IsWithinDistInMap(playerGroup,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
  226.                     playersNear.push_back(playerGroup);
  227.             }
  228.  
  229.             uint32 money_per_player = uint32((pLoot->gold)/(playersNear.size()));
  230.  
  231.             for (std::vector<Player*>::const_iterator i = playersNear.begin(); i != playersNear.end(); ++i)
  232.             {
  233.                 (*i)->ModifyMoney( money_per_player );
  234.                 (*i)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, money_per_player);
  235.                 //Offset surely incorrect, but works
  236.                 WorldPacket data( SMSG_LOOT_MONEY_NOTIFY, 4 );
  237.                 data << uint32(money_per_player);
  238.                 (*i)->GetSession()->SendPacket( &data );
  239.             }
  240.         }
  241.         else
  242.         {
  243.             player->ModifyMoney( pLoot->gold );
  244.             player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, pLoot->gold);
  245.         }
  246.         pLoot->gold = 0;
  247.         pLoot->NotifyMoneyRemoved();
  248.     }
  249. }
  250.  
  251. void WorldSession::HandleLootOpcode( WorldPacket & recv_data )
  252. {
  253.     sLog.outDebug("WORLD: CMSG_LOOT");
  254.  
  255.     uint64 guid;
  256.     recv_data >> guid;
  257.  
  258.     // Check possible cheat
  259.     if(!_player->isAlive())
  260.         return;
  261.  
  262.     GetPlayer()->SendLoot(guid, LOOT_CORPSE);
  263. }
  264.  
  265. void WorldSession::HandleLootReleaseOpcode( WorldPacket & recv_data )
  266. {
  267.     sLog.outDebug("WORLD: CMSG_LOOT_RELEASE");
  268.  
  269.     // cheaters can modify lguid to prevent correct apply loot release code and re-loot
  270.     // use internal stored guid
  271.     recv_data.read_skip<uint64>();                          // guid;
  272.  
  273.     if(uint64 lguid = GetPlayer()->GetLootGUID())
  274.         DoLootRelease(lguid);
  275. }
  276.  
  277. void WorldSession::DoLootRelease( uint64 lguid )
  278. {
  279.     Player  *player = GetPlayer();
  280.     Loot    *loot;
  281.  
  282.     player->SetLootGUID(0);
  283.     player->SendLootRelease(lguid);
  284.  
  285.     player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING);
  286.  
  287.     if(!player->IsInWorld())
  288.         return;
  289.  
  290.     if (IS_GAMEOBJECT_GUID(lguid))
  291.     {
  292.         GameObject *go = GetPlayer()->GetMap()->GetGameObject(lguid);
  293.  
  294.         // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
  295.         if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player,INTERACTION_DISTANCE)))
  296.             return;
  297.  
  298.         loot = &go->loot;
  299.  
  300.         if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR)
  301.         {
  302.             // locked doors are opened with spelleffect openlock, prevent remove its as looted
  303.             go->UseDoorOrButton();
  304.         }
  305.         else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE)
  306.         {
  307.             // GO is mineral vein? so it is not removed after its looted
  308.             if(go->GetGoType() == GAMEOBJECT_TYPE_CHEST)
  309.             {
  310.                 uint32 go_min = go->GetGOInfo()->chest.minSuccessOpens;
  311.                 uint32 go_max = go->GetGOInfo()->chest.maxSuccessOpens;
  312.  
  313.                 // only vein pass this check
  314.                 if(go_min != 0 && go_max > go_min)
  315.                 {
  316.                     float amount_rate = sWorld.getRate(RATE_MINING_AMOUNT);
  317.                     float min_amount = go_min*amount_rate;
  318.                     float max_amount = go_max*amount_rate;
  319.  
  320.                     go->AddUse();
  321.                     float uses = float(go->GetUseCount());
  322.  
  323.                     if(uses < max_amount)
  324.                     {
  325.                         if(uses >= min_amount)
  326.                         {
  327.                             float chance_rate = sWorld.getRate(RATE_MINING_NEXT);
  328.  
  329.                             int32 ReqValue = 175;
  330.                             LockEntry const *lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId);
  331.                             if(lockInfo)
  332.                                 ReqValue = lockInfo->Skill[0];
  333.                             float skill = float(player->GetSkillValue(SKILL_MINING))/(ReqValue+25);
  334.                             double chance = pow(0.8*chance_rate,4*(1/double(max_amount))*double(uses));
  335.                             if(roll_chance_f(100*chance+skill))
  336.                             {
  337.                                 go->SetLootState(GO_READY);
  338.                             }
  339.                             else                            // not have more uses
  340.                                 go->SetLootState(GO_JUST_DEACTIVATED);
  341.                         }
  342.                         else                                // 100% chance until min uses
  343.                             go->SetLootState(GO_READY);
  344.                     }
  345.                     else                                    // max uses already
  346.                         go->SetLootState(GO_JUST_DEACTIVATED);
  347.                 }
  348.                 else                                        // not vein
  349.                     go->SetLootState(GO_JUST_DEACTIVATED);
  350.             }
  351.             else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE)
  352.             {                                               // The fishing hole used once more
  353.                 go->AddUse();                               // if the max usage is reached, will be despawned in next tick
  354.                 if (go->GetUseCount()>=irand(go->GetGOInfo()->fishinghole.minSuccessOpens,go->GetGOInfo()->fishinghole.maxSuccessOpens))
  355.                 {
  356.                     go->SetLootState(GO_JUST_DEACTIVATED);
  357.                 }
  358.                 else
  359.                     go->SetLootState(GO_READY);
  360.             }
  361.             else // not chest (or vein/herb/etc)
  362.                 go->SetLootState(GO_JUST_DEACTIVATED);
  363.  
  364.             loot->clear();
  365.         }
  366.         else
  367.             // not fully looted object
  368.             go->SetLootState(GO_ACTIVATED);
  369.     }
  370.     else if (IS_CORPSE_GUID(lguid))        // ONLY remove insignia at BG
  371.     {
  372.         Corpse *corpse = ObjectAccessor::GetCorpse(*player, lguid);
  373.         if (!corpse || !corpse->IsWithinDistInMap(_player,INTERACTION_DISTANCE) )
  374.             return;
  375.  
  376.         loot = &corpse->loot;
  377.  
  378.         if (loot->isLooted())
  379.         {
  380.             loot->clear();
  381.             corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE);
  382.         }
  383.     }
  384.     else if (IS_ITEM_GUID(lguid))
  385.     {
  386.         Item *pItem = player->GetItemByGuid(lguid );
  387.         if(!pItem)
  388.             return;
  389.  
  390.         ItemPrototype const* proto = pItem->GetProto();
  391.  
  392.         // destroy only 5 items from stack in case prospecting and milling
  393.         if( (proto->BagFamily & (BAG_FAMILY_MASK_MINING_SUPP|BAG_FAMILY_MASK_HERBS)) &&
  394.             proto->Class == ITEM_CLASS_TRADE_GOODS)
  395.         {
  396.             pItem->m_lootGenerated = false;
  397.             pItem->loot.clear();
  398.  
  399.             uint32 count = pItem->GetCount();
  400.  
  401.             // >=5 checked in spell code, but will work for cheating cases also with removing from another stacks.
  402.             if(count > 5)
  403.                 count = 5;
  404.  
  405.             player->DestroyItemCount(pItem, count, true);
  406.         }
  407.         else
  408.             // FIXME: item don't must be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or checting possible.
  409.             player->DestroyItem( pItem->GetBagSlot(),pItem->GetSlot(), true);
  410.         return;                                             // item can be looted only single player
  411.     }
  412.     else
  413.     {
  414.         Creature* pCreature = GetPlayer()->GetMap()->GetCreature(lguid);
  415.  
  416.         bool ok_loot = pCreature && pCreature->isAlive() == (player->getClass()==CLASS_ROGUE && pCreature->lootForPickPocketed);
  417.         if ( !ok_loot || !pCreature->IsWithinDistInMap(_player,INTERACTION_DISTANCE) )
  418.             return;
  419.  
  420.         loot = &pCreature->loot;
  421.  
  422.         // update next looter
  423.         if(Player *recipient = pCreature->GetLootRecipient())
  424.             if(Group* group = recipient->GetGroup())
  425.                 if (group->GetLooterGuid() == player->GetGUID())
  426.                     group->UpdateLooterGuid(pCreature);
  427.  
  428.         if (loot->isLooted())
  429.         {
  430.             // skip pickpocketing loot for speed, skinning timer redunction is no-op in fact
  431.             if(!pCreature->isAlive())
  432.                 pCreature->AllLootRemovedFromCorpse();
  433.  
  434.             pCreature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
  435.             loot->clear();
  436.         }
  437.     }
  438.  
  439.     //Player is not looking at loot list, he doesn't need to see updates on the loot list
  440.     loot->RemoveLooter(player->GetGUID());
  441. }
  442.  
  443. void WorldSession::HandleLootMasterGiveOpcode( WorldPacket & recv_data )
  444. {
  445.     uint8 slotid;
  446.     uint64 lootguid, target_playerguid;
  447.  
  448.     recv_data >> lootguid >> slotid >> target_playerguid;
  449.  
  450.     if(!_player->GetGroup() || _player->GetGroup()->GetLooterGuid() != _player->GetGUID())
  451.     {
  452.         _player->SendLootRelease(GetPlayer()->GetLootGUID());
  453.         return;
  454.     }
  455.  
  456.     Player *target = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(target_playerguid, 0, HIGHGUID_PLAYER));
  457.     if(!target)
  458.         return;
  459.  
  460.     sLog.outDebug("WorldSession::HandleLootMasterGiveOpcode (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [%s].", target->GetName());
  461.  
  462.     if(_player->GetLootGUID() != lootguid)
  463.         return;
  464.  
  465.     Loot *pLoot = NULL;
  466.  
  467.     if(IS_CRE_OR_VEH_GUID(GetPlayer()->GetLootGUID()))
  468.     {
  469.         Creature *pCreature = GetPlayer()->GetMap()->GetCreature(lootguid);
  470.         if(!pCreature)
  471.             return;
  472.  
  473.         pLoot = &pCreature->loot;
  474.     }
  475.     else if(IS_GAMEOBJECT_GUID(GetPlayer()->GetLootGUID()))
  476.     {
  477.         GameObject *pGO = GetPlayer()->GetMap()->GetGameObject(lootguid);
  478.         if(!pGO)
  479.             return;
  480.  
  481.         pLoot = &pGO->loot;
  482.     }
  483.  
  484.     if(!pLoot)
  485.         return;
  486.  
  487.     if (slotid > pLoot->items.size())
  488.     {
  489.         sLog.outDebug("AutoLootItem: Player %s might be using a hack! (slot %d, size %lu)",GetPlayer()->GetName(), slotid, (unsigned long)pLoot->items.size());
  490.         return;
  491.     }
  492.  
  493.     LootItem& item = pLoot->items[slotid];
  494.  
  495.     ItemPosCountVec dest;
  496.     uint8 msg = target->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item.itemid, item.count );
  497.     if ( msg != EQUIP_ERR_OK )
  498.     {
  499.         target->SendEquipError( msg, NULL, NULL );
  500.         _player->SendEquipError( msg, NULL, NULL );         // send duplicate of error massage to master looter
  501.         return;
  502.     }
  503.  
  504.     // not move item from loot to target inventory
  505.     Item * newitem = target->StoreNewItem( dest, item.itemid, true, item.randomPropertyId );
  506.     target->SendNewItem(newitem, uint32(item.count), false, false, true );
  507.     target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item.itemid, item.count);
  508.     target->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, pLoot->loot_type, item.count);
  509.  
  510.     // mark as looted
  511.     item.count=0;
  512.     item.is_looted=true;
  513.  
  514.     pLoot->NotifyItemRemoved(slotid);
  515.     --pLoot->unlootedCount;
  516. }