diff options
| author | Subv <s.v.h21@hotmail.com> | 2012-12-23 08:33:13 -0500 |
|---|---|---|
| committer | Subv <s.v.h21@hotmail.com> | 2012-12-23 08:33:13 -0500 |
| commit | 3869bb7b3a96751b463ecec2d9ac663b792a0703 (patch) | |
| tree | 330d7e96fa4021f6301d488d64ac6eed717172ab /src/server/game | |
| parent | d40cbe0113329de96723e8fe015651c919760a15 (diff) | |
| parent | 143340b38c857b2cc50ee9f8577abf9248b6317a (diff) | |
Merge branch 'master' of https://github.com/TrinityCore/TrinityCore into 4.3.4
Conflicts:
src/server/game/Entities/Item/Item.cpp
src/server/game/Entities/Player/Player.cpp
src/server/game/Entities/Player/Player.h
Diffstat (limited to 'src/server/game')
| -rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 188 | ||||
| -rw-r--r-- | src/server/game/Entities/Item/Item.h | 9 | ||||
| -rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 7 | ||||
| -rw-r--r-- | src/server/game/Entities/Pet/Pet.cpp | 8 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 270 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.h | 2 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 151 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 1 | ||||
| -rw-r--r-- | src/server/game/Handlers/CharacterHandler.cpp | 18 | ||||
| -rw-r--r-- | src/server/game/Handlers/LootHandler.cpp | 18 | ||||
| -rw-r--r-- | src/server/game/Loot/LootMgr.cpp | 41 | ||||
| -rw-r--r-- | src/server/game/Loot/LootMgr.h | 16 | ||||
| -rw-r--r-- | src/server/game/Maps/Map.cpp | 2 | ||||
| -rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.cpp | 2 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 18 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellMgr.cpp | 3 | ||||
| -rw-r--r-- | src/server/game/Tools/PlayerDump.cpp | 1 |
17 files changed, 491 insertions, 264 deletions
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index eec50095a91..bd006ba3e05 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -383,6 +383,10 @@ void Item::SaveToDB(SQLTransaction& trans) if (!isInTransaction) CharacterDatabase.CommitTransaction(trans); + // Delete the items if this is a container + if (!loot.isLooted()) + ItemContainerDeleteLootMoneyAndLootItemsFromDB(); + delete this; return; } @@ -488,6 +492,10 @@ void Item::DeleteFromDB(SQLTransaction& trans, uint32 itemGuid) void Item::DeleteFromDB(SQLTransaction& trans) { DeleteFromDB(trans, GetGUIDLow()); + + // Delete the items if this is a container + if (!loot.isLooted()) + ItemContainerDeleteLootMoneyAndLootItemsFromDB(); } /*static*/ @@ -1483,3 +1491,183 @@ int32 Item::GetReforgableStat(ItemModType statType) const return 0; } + +void Item::ItemContainerSaveLootToDB() +{ + // Saves the money and item loot associated with an openable item to the DB + if (loot.isLooted()) // no money and no loot + return; + + uint32 container_id = GetGUIDLow(); + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + + loot.containerID = container_id; // Save this for when a LootItem is removed + + // Save money + if (loot.gold > 0) + { + PreparedStatement* stmt_money = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY); + stmt_money->setUInt32(0, container_id); + trans->Append(stmt_money); + + stmt_money = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_MONEY); + stmt_money->setUInt32(0, container_id); + stmt_money->setUInt32(1, loot.gold); + trans->Append(stmt_money); + } + + // Save items + if (!loot.isLooted()) + { + PreparedStatement* stmt_items = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS); + stmt_items->setUInt32(0, container_id); + trans->Append(stmt_items); + + // Now insert the items + for (LootItemList::const_iterator _li = loot.items.begin(); _li != loot.items.end(); _li++) + { + // When an item is looted, it doesn't get removed from the items collection + // but we don't want to resave it. + if (!_li->canSave) + continue; + + stmt_items = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_ITEMS); + + // container_id, item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix + stmt_items->setUInt32(0, container_id); + stmt_items->setUInt32(1, _li->itemid); + stmt_items->setUInt32(2, _li->count); + stmt_items->setBool(3, _li->follow_loot_rules); + stmt_items->setBool(4, _li->freeforall); + stmt_items->setBool(5, _li->is_blocked); + stmt_items->setBool(6, _li->is_counted); + stmt_items->setBool(7, _li->is_underthreshold); + stmt_items->setBool(8, _li->needs_quest); + stmt_items->setUInt32(9, _li->randomPropertyId); + stmt_items->setUInt32(10, _li->randomSuffix); + trans->Append(stmt_items); + } + } + + CharacterDatabase.CommitTransaction(trans); +} + +bool Item::ItemContainerLoadLootFromDB() +{ + // Loads the money and item loot associated with an openable item from the DB + // Default. If there are no records for this item then it will be rolled for in Player::SendLoot() + m_lootGenerated = false; + + uint32 container_id = GetGUIDLow(); + + // Save this for later use + loot.containerID = container_id; + + // First, see if there was any money loot. This gets added directly to the container. + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_MONEY); + stmt->setUInt32(0, container_id); + PreparedQueryResult money_result = CharacterDatabase.Query(stmt); + + if (money_result) + { + Field* fields = money_result->Fetch(); + loot.gold = fields[0].GetUInt32(); + } + + // Next, load any items that were saved + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_ITEMS); + stmt->setUInt32(0, container_id); + PreparedQueryResult item_result = CharacterDatabase.Query(stmt); + + if (item_result) + { + // Get a LootTemplate for the container item. This is where + // the saved loot was originally rolled from, we will copy conditions from it + LootTemplate const* lt = LootTemplates_Item.GetLootFor(GetEntry()); + if (lt) + { + do + { + // Create an empty LootItem + LootItem loot_item = LootItem(); + + // Fill in the rest of the LootItem from the DB + Field* fields = item_result->Fetch(); + + // item_id, itm_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix + loot_item.itemid = fields[0].GetUInt32(); + loot_item.count = fields[1].GetUInt32(); + loot_item.follow_loot_rules = fields[2].GetBool(); + loot_item.freeforall = fields[3].GetBool(); + loot_item.is_blocked = fields[4].GetBool(); + loot_item.is_counted = fields[5].GetBool(); + loot_item.canSave = true; + loot_item.is_underthreshold = fields[6].GetBool(); + loot_item.needs_quest = fields[7].GetBool(); + loot_item.randomPropertyId = fields[8].GetUInt32(); + loot_item.randomSuffix = fields[9].GetUInt32(); + + // Copy the extra loot conditions from the item in the loot template + lt->CopyConditions(&loot_item); + + // If container item is in a bag, add that player as an allowed looter + if (GetBagSlot()) + loot_item.allowedGUIDs.insert(GetOwner()->GetGUIDLow()); + + // Finally add the LootItem to the container + loot.items.push_back(loot_item); + + // Increment unlooted count + loot.unlootedCount++; + + } + while (item_result->NextRow()); + } + } + + // Mark the item if it has loot so it won't be generated again on open + m_lootGenerated = !loot.isLooted(); + + return m_lootGenerated; +} + +void Item::ItemContainerDeleteLootItemsFromDB() +{ + // Deletes items associated with an openable item from the DB + uint32 containerId = GetGUIDLow(); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS); + stmt->setUInt32(0, containerId); + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + trans->Append(stmt); + CharacterDatabase.CommitTransaction(trans); +} + +void Item::ItemContainerDeleteLootItemFromDB(uint32 itemID) +{ + // Deletes a single item associated with an openable item from the DB + uint32 containerId = GetGUIDLow(); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM); + stmt->setUInt32(0, containerId); + stmt->setUInt32(1, itemID); + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + trans->Append(stmt); + CharacterDatabase.CommitTransaction(trans); +} + +void Item::ItemContainerDeleteLootMoneyFromDB() +{ + // Deletes the money loot associated with an openable item from the DB + uint32 containerId = GetGUIDLow(); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY); + stmt->setUInt32(0, containerId); + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + trans->Append(stmt); + CharacterDatabase.CommitTransaction(trans); +} + +void Item::ItemContainerDeleteLootMoneyAndLootItemsFromDB() +{ + // Deletes money and items associated with an openable item from the DB + ItemContainerDeleteLootMoneyFromDB(); + ItemContainerDeleteLootItemsFromDB(); +} diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 3927676af47..6550535e5fe 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -238,6 +238,15 @@ class Item : public Object static void DeleteFromDB(SQLTransaction& trans, uint32 itemGuid); virtual void DeleteFromDB(SQLTransaction& trans); static void DeleteFromInventoryDB(SQLTransaction& trans, uint32 itemGuid); + + // Lootable items and their contents + void ItemContainerSaveLootToDB(); + bool ItemContainerLoadLootFromDB(); + void ItemContainerDeleteLootItemsFromDB(); + void ItemContainerDeleteLootItemFromDB(uint32 itemID); + void ItemContainerDeleteLootMoneyFromDB(); + void ItemContainerDeleteLootMoneyAndLootItemsFromDB(); + void DeleteFromInventoryDB(SQLTransaction& trans); void SaveRefundDataToDB(); void DeleteRefundDataFromDB(SQLTransaction* trans); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 30f64b0b30e..1e255890178 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -2488,12 +2488,7 @@ void WorldObject::SetZoneScript() if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(GetZoneId())) m_zoneScript = bf; else - { - if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(GetZoneId())) - m_zoneScript = bf; - else - m_zoneScript = sOutdoorPvPMgr->GetZoneScript(GetZoneId()); - } + m_zoneScript = sOutdoorPvPMgr->GetZoneScript(GetZoneId()); } } } diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 5dcc0246651..a14cc212555 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -267,7 +267,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c { SQLTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_PET_SLOT_BY_SLOT_EXCLUDE_ID); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_PET_SLOT_BY_SLOT_EXCLUDE_ID); stmt->setUInt8(0, uint8(PET_SAVE_NOT_IN_SLOT)); stmt->setUInt32(1, ownerid); stmt->setUInt8(2, uint8(PET_SAVE_AS_CURRENT)); @@ -332,7 +332,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c if (getPetType() == HUNTER_PET) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_DECLINED_NAME); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_DECLINED_NAME); stmt->setUInt32(0, owner->GetGUIDLow()); stmt->setUInt32(1, GetCharmInfo()->GetPetNumber()); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -428,7 +428,7 @@ void Pet::SavePetToDB(PetSaveMode mode) // prevent existence another hunter pet in PET_SAVE_AS_CURRENT and PET_SAVE_NOT_IN_SLOT if (getPetType() == HUNTER_PET && (mode == PET_SAVE_AS_CURRENT || mode > PET_SAVE_LAST_STABLE_SLOT)) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_BY_SLOT); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_BY_SLOT); stmt->setUInt32(0, ownerLowGUID); stmt->setUInt8(1, uint8(PET_SAVE_AS_CURRENT)); stmt->setUInt8(2, uint8(PET_SAVE_LAST_STABLE_SLOT)); @@ -1308,7 +1308,7 @@ void Pet::_SaveAuras(SQLTransaction& trans) uint8 index = 0; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET_AURA); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET_AURA); stmt->setUInt32(index++, m_charmInfo->GetPetNumber()); stmt->setUInt64(index++, casterGUID); stmt->setUInt32(index++, itr->second->GetId()); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 222fa6c1c74..42e6d38aca6 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2078,66 +2078,6 @@ uint8 Player::GetChatTag() const return tag; } -void Player::SendTeleportPacket(Position &oldPos) -{ - ObjectGuid guid = GetGUID(); - ObjectGuid transGuid = GetTransGUID(); - - WorldPacket data(MSG_MOVE_TELEPORT, 38); - data.WriteBit(guid[6]); - data.WriteBit(guid[0]); - data.WriteBit(guid[3]); - data.WriteBit(guid[2]); - data.WriteBit(0); // unknown - data.WriteBit(uint64(transGuid)); - data.WriteBit(guid[1]); - if (transGuid) - { - data.WriteBit(transGuid[1]); - data.WriteBit(transGuid[3]); - data.WriteBit(transGuid[2]); - data.WriteBit(transGuid[5]); - data.WriteBit(transGuid[0]); - data.WriteBit(transGuid[7]); - data.WriteBit(transGuid[6]); - data.WriteBit(transGuid[4]); - } - - data.WriteBit(guid[4]); - data.WriteBit(guid[7]); - data.WriteBit(guid[5]); - data.FlushBits(); - - if (transGuid) - { - data.WriteByteSeq(transGuid[6]); - data.WriteByteSeq(transGuid[5]); - data.WriteByteSeq(transGuid[1]); - data.WriteByteSeq(transGuid[7]); - data.WriteByteSeq(transGuid[0]); - data.WriteByteSeq(transGuid[2]); - data.WriteByteSeq(transGuid[4]); - data.WriteByteSeq(transGuid[3]); - } - - data << uint32(0); // counter - data.WriteByteSeq(guid[1]); - data.WriteByteSeq(guid[2]); - data.WriteByteSeq(guid[3]); - data.WriteByteSeq(guid[5]); - data << float(GetPositionX()); - data.WriteByteSeq(guid[4]); - data << float(GetOrientation()); - data.WriteByteSeq(guid[7]); - data << float(GetPositionZMinusOffset()); - data.WriteByteSeq(guid[0]); - data.WriteByteSeq(guid[6]); - data << float(GetPositionY()); - - Relocate(&oldPos); - SendDirectMessage(&data); -} - bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options) { if (!MapManager::IsValidMapCoord(mapid, x, y, z, orientation)) @@ -4809,7 +4749,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC // We can return mail now // So firstly delete the old one - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID); stmt->setUInt32(0, mail_id); trans->Append(stmt); @@ -4818,7 +4758,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC { if (has_items) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID); stmt->setUInt32(0, mail_id); trans->Append(stmt); } @@ -4832,7 +4772,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC if (has_items) { // Data needs to be at first place for Item::LoadFromDB - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS); stmt->setUInt32(0, mail_id); PreparedQueryResult resultItems = CharacterDatabase.Query(stmt); if (resultItems) @@ -5047,7 +4987,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC // The character gets unlinked from the account, the name gets freed up and appears as deleted ingame case CHAR_DELETE_UNLINK: { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_DELETE_INFO); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_DELETE_INFO); stmt->setUInt32(0, guid); @@ -5755,7 +5695,7 @@ void Player::HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, floa float Player::GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const { - if (modGroup >= BASEMOD_END || modType > MOD_END) + if (modGroup >= BASEMOD_END || modType >= MOD_END) { sLog->outError(LOG_FILTER_SPELLS_AURAS, "trial to access non existed BaseModGroup or wrong BaseModType!"); return 0.0f; @@ -6968,7 +6908,10 @@ int32 Player::CalculateReputationGain(ReputationSource source, uint32 creatureOr percent *= repRate; } - return int32(rep * percent / 100.0f); + if (source != REPUTATION_SOURCE_SPELL && GetsRecruitAFriendBonus(false)) + percent *= 1.0f + sWorld->getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS); + + return CalculatePct(rep, percent); } // Calculates how many reputation points player gains in victim's enemy factions @@ -6991,43 +6934,20 @@ void Player::RewardReputation(Unit* victim, float rate) // support for: Championing - http://www.wowwiki.com/Championing Map const* map = GetMap(); - if (map && map->IsDungeon()) + if (map && map->IsNonRaidDungeon()) { - InstanceTemplate const* instance = sObjectMgr->GetInstanceTemplate(map->GetId()); - if (instance) - { - AccessRequirement const* pAccessRequirement = sObjectMgr->GetAccessRequirement(map->GetId(), ((InstanceMap*)map)->GetDifficulty()); - if (pAccessRequirement) - { - if (!map->IsRaid() && pAccessRequirement->levelMin == 80) - ChampioningFaction = GetChampioningFaction(); - } - } + if (AccessRequirement const* accessRequirement = sObjectMgr->GetAccessRequirement(map->GetId(), map->GetDifficulty())) + if (accessRequirement->levelMin == 80) + ChampioningFaction = GetChampioningFaction(); } } - // Favored reputation increase START - uint32 zone = GetZoneId(); uint32 team = GetTeam(); - float favored_rep_mult = 0; - - if ((HasAura(32096) || HasAura(32098)) && (zone == 3483 || zone == 3562 || zone == 3836 || zone == 3713 || zone == 3714)) - favored_rep_mult = 0.25; // Thrallmar's Favor and Honor Hold's Favor - else if (HasAura(30754) && (Rep->RepFaction1 == 609 || Rep->RepFaction2 == 609) && !ChampioningFaction) - favored_rep_mult = 0.25; // Cenarion Favor - - if (favored_rep_mult > 0) favored_rep_mult *= 2; // Multiplied by 2 because the reputation is divided by 2 for some reason (See "donerep1 / 2" and "donerep2 / 2") -- if you know why this is done, please update/explain :) - // Favored reputation increase END - - bool recruitAFriend = GetsRecruitAFriendBonus(false); if (Rep->RepFaction1 && (!Rep->TeamDependent || team == ALLIANCE)) { int32 donerep1 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->getLevel(), Rep->RepValue1, ChampioningFaction ? ChampioningFaction : Rep->RepFaction1); - donerep1 = int32(donerep1*(rate + favored_rep_mult)); - - if (recruitAFriend) - donerep1 = int32(donerep1 * (1 + sWorld->getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS))); + donerep1 = int32(donerep1 * rate); FactionEntry const* factionEntry1 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction1); uint32 current_reputation_rank1 = GetReputationMgr().GetRank(factionEntry1); @@ -7038,10 +6958,7 @@ void Player::RewardReputation(Unit* victim, float rate) if (Rep->RepFaction2 && (!Rep->TeamDependent || team == HORDE)) { int32 donerep2 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->getLevel(), Rep->RepValue2, ChampioningFaction ? ChampioningFaction : Rep->RepFaction2); - donerep2 = int32(donerep2*(rate + favored_rep_mult)); - - if (recruitAFriend) - donerep2 = int32(donerep2 * (1 + sWorld->getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS))); + donerep2 = int32(donerep2 * rate); FactionEntry const* factionEntry2 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction2); uint32 current_reputation_rank2 = GetReputationMgr().GetRank(factionEntry2); @@ -7053,59 +6970,43 @@ void Player::RewardReputation(Unit* victim, float rate) // Calculate how many reputation points player gain with the quest void Player::RewardReputation(Quest const* quest) { - bool recruitAFriend = GetsRecruitAFriendBonus(false); - - // quest reputation reward/loss for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) { if (!quest->RewardFactionId[i]) continue; - if (quest->RewardFactionValueIdOverride[i]) - { - int32 rep = 0; - if (quest->IsDaily()) - rep = CalculateReputationGain(REPUTATION_SOURCE_DAILY_QUEST, GetQuestLevel(quest), quest->RewardFactionValueIdOverride[i]/100, quest->RewardFactionId[i], true); - else if (quest->IsWeekly()) - rep = CalculateReputationGain(REPUTATION_SOURCE_WEEKLY_QUEST, GetQuestLevel(quest), quest->RewardFactionValueIdOverride[i]/100, quest->RewardFactionId[i], true); - else if (quest->IsMonthly()) - rep = CalculateReputationGain(REPUTATION_SOURCE_MONTHLY_QUEST, GetQuestLevel(quest), quest->RewardFactionValueIdOverride[i]/100, quest->RewardFactionId[i], true); - else - rep = CalculateReputationGain(REPUTATION_SOURCE_QUEST, GetQuestLevel(quest), quest->RewardFactionValueIdOverride[i]/100, quest->RewardFactionId[i], true); - - if (recruitAFriend) - rep = int32(rep * (1 + sWorld->getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS))); + int32 rep = 0; + bool noQuestBonus = false; - if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(quest->RewardFactionId[i])) - GetReputationMgr().ModifyReputation(factionEntry, rep); + if (quest->RewardFactionValueIdOverride[i]) + { + rep = quest->RewardFactionValueIdOverride[i] / 100; + noQuestBonus = true; } else { uint32 row = ((quest->RewardFactionValueId[i] < 0) ? 1 : 0) + 1; - uint32 field = abs(quest->RewardFactionValueId[i]); - - if (QuestFactionRewEntry const* pRow = sQuestFactionRewardStore.LookupEntry(row)) + if (QuestFactionRewEntry const* questFactionRewEntry = sQuestFactionRewardStore.LookupEntry(row)) { - int32 repPoints = pRow->QuestRewFactionValue[field]; - if (!repPoints) - continue; + uint32 field = abs(quest->RewardFactionValueId[i]); + rep = questFactionRewEntry->QuestRewFactionValue[field]; + } + } - if (quest->IsDaily()) - repPoints = CalculateReputationGain(REPUTATION_SOURCE_DAILY_QUEST, GetQuestLevel(quest), repPoints, quest->RewardFactionId[i]); - else if (quest->IsWeekly()) - repPoints = CalculateReputationGain(REPUTATION_SOURCE_WEEKLY_QUEST, GetQuestLevel(quest), repPoints, quest->RewardFactionId[i]); - else if (quest->IsMonthly()) - repPoints = CalculateReputationGain(REPUTATION_SOURCE_MONTHLY_QUEST, GetQuestLevel(quest), repPoints, quest->RewardFactionId[i]); - else - repPoints = CalculateReputationGain(REPUTATION_SOURCE_QUEST, GetQuestLevel(quest), repPoints, quest->RewardFactionId[i]); + if (!rep) + continue; - if (recruitAFriend) - repPoints = int32(repPoints * (1 + sWorld->getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS))); + if (quest->IsDaily()) + rep = CalculateReputationGain(REPUTATION_SOURCE_DAILY_QUEST, GetQuestLevel(quest), rep, quest->RewardFactionId[i], noQuestBonus); + else if (quest->IsWeekly()) + rep = CalculateReputationGain(REPUTATION_SOURCE_WEEKLY_QUEST, GetQuestLevel(quest), rep, quest->RewardFactionId[i], noQuestBonus); + else if (quest->IsMonthly()) + rep = CalculateReputationGain(REPUTATION_SOURCE_MONTHLY_QUEST, GetQuestLevel(quest), rep, quest->RewardFactionId[i], noQuestBonus); + else + rep = CalculateReputationGain(REPUTATION_SOURCE_QUEST, GetQuestLevel(quest), rep, quest->RewardFactionId[i], noQuestBonus); - if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(quest->RewardFactionId[i])) - GetReputationMgr().ModifyReputation(factionEntry, repPoints); - } - } + if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(quest->RewardFactionId[i])) + GetReputationMgr().ModifyReputation(factionEntry, rep); } } @@ -7765,7 +7666,7 @@ uint32 Player::GetZoneIdFromDB(uint64 guid) if (!zone) { // stored zone is zero, use generic and slow zone detection - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_POSITION_XYZ); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_POSITION_XYZ); stmt->setUInt32(0, guidLow); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -7781,7 +7682,7 @@ uint32 Player::GetZoneIdFromDB(uint64 guid) if (zone > 0) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ZONE); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ZONE); stmt->setUInt16(0, uint16(zone)); stmt->setUInt32(1, guidLow); @@ -8691,25 +8592,11 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 if (proto->SpellPPMRate) { - if (spellData.SpellId == 52781) // Persuasive Strike - { - switch (target->GetEntry()) - { - default: - return; - case 28939: - case 28940: - case 28610: - break; - } - } uint32 WeaponSpeed = GetAttackTime(attType); chance = GetPPMProcChance(WeaponSpeed, proto->SpellPPMRate, spellInfo); } else if (chance > 100.0f) - { chance = GetWeaponProcChance(); - } if (roll_chance_f(chance)) CastSpell(target, spellInfo->Id, true, item); @@ -9143,7 +9030,9 @@ void Player::SendLoot(uint64 guid, LootType loot_type) loot = &item->loot; - if (!item->m_lootGenerated) + // If item doesn't already have loot, attempt to load it. If that + // fails then this is first time opening, generate loot + if (!item->m_lootGenerated && !item->ItemContainerLoadLootFromDB()) { item->m_lootGenerated = true; loot->clear(); @@ -9162,6 +9051,12 @@ void Player::SendLoot(uint64 guid, LootType loot_type) default: loot->generateMoneyLoot(item->GetTemplate()->MinMoneyLoot, item->GetTemplate()->MaxMoneyLoot); loot->FillLoot(item->GetEntry(), LootTemplates_Item, this, true, loot->gold != 0); + + // Force save the loot and money items that were just rolled + // Also saves the container item ID in Loot struct (not to DB) + if (loot->gold > 0 || loot->unlootedCount > 0) + item->ItemContainerSaveLootToDB(); + break; } } @@ -9884,8 +9779,8 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) instance->FillInitialWorldStates(data); else { - data << uint32(4132) << uint32(0); // 9 WORLDSTATE_SHOW_CRATES - data << uint32(4131) << uint32(0); // 10 WORLDSTATE_CRATES_REVEALED + data << uint32(4132) << uint32(0); // 9 WORLDSTATE_ALGALON_TIMER_ENABLED + data << uint32(4131) << uint32(0); // 10 WORLDSTATE_ALGALON_DESPAWN_TIMER } break; // Twin Peaks @@ -10048,11 +9943,10 @@ void Player::SetSheath(SheathState sheathed) SetVirtualItemSlot(2, NULL); break; case SHEATH_STATE_MELEE: // prepared melee weapon - { SetVirtualItemSlot(0, GetWeaponForAttack(BASE_ATTACK, true)); SetVirtualItemSlot(1, GetWeaponForAttack(OFF_ATTACK, true)); SetVirtualItemSlot(2, NULL); - }; break; + break; case SHEATH_STATE_RANGED: // prepared ranged weapon SetVirtualItemSlot(0, NULL); SetVirtualItemSlot(1, NULL); @@ -11875,7 +11769,7 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje Map const* map = lootedObject->GetMap(); if (uint32 dungeonId = sLFGMgr->GetDungeon(GetGroup()->GetGUID(), true)) if (LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId)) - if (uint32(dungeon->map) == map->GetId() && dungeon->difficulty == uint32(map->GetDifficulty())) + if (uint32(dungeon->map) == map->GetId() && dungeon->difficulty == map->GetDifficulty()) lootedObjectInDungeon = true; if (!lootedObjectInDungeon) @@ -12204,12 +12098,12 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update) switch (slot) { - case EQUIPMENT_SLOT_MAINHAND: - case EQUIPMENT_SLOT_OFFHAND: - case EQUIPMENT_SLOT_RANGED: - RecalculateRating(CR_ARMOR_PENETRATION); - default: - break; + case EQUIPMENT_SLOT_MAINHAND: + case EQUIPMENT_SLOT_OFFHAND: + case EQUIPMENT_SLOT_RANGED: + RecalculateRating(CR_ARMOR_PENETRATION); + default: + break; } } else @@ -12513,6 +12407,12 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update) else if (Bag* pBag = GetBagByPos(bag)) pBag->RemoveItem(slot, update); + // Delete rolled money / loot from db. + // MUST be done before RemoveFromWorld() or GetTemplate() fails + if (ItemTemplate const* pTmp = pItem->GetTemplate()) + if (pTmp->Flags & ITEM_PROTO_FLAG_OPENABLE) + pItem->ItemContainerDeleteLootMoneyAndLootItemsFromDB(); + if (IsInWorld() && update) { pItem->RemoveFromWorld(); @@ -17972,7 +17872,7 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F } else { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_REFUNDS); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_REFUNDS); stmt->setUInt32(0, item->GetGUIDLow()); stmt->setUInt32(1, GetGUIDLow()); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) @@ -17992,7 +17892,7 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F } else if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE)) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_BOP_TRADE); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_BOP_TRADE); stmt->setUInt32(0, item->GetGUIDLow()); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) { @@ -18596,11 +18496,12 @@ InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, b if (save) { InstancePlayerBind& bind = m_boundInstances[save->GetDifficulty()][save->GetMapId()]; - if (bind.save) + if (!load) { - // update the save when the group kills a boss - if (permanent != bind.perm || save != bind.save) - if (!load) + if (bind.save) + { + // update the save when the group kills a boss + if (permanent != bind.perm || save != bind.save) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_INSTANCE); @@ -18611,9 +18512,8 @@ InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, b CharacterDatabase.Execute(stmt); } - } - else - if (!load) + } + else { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_INSTANCE); @@ -18623,6 +18523,7 @@ InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, b CharacterDatabase.Execute(stmt); } + } if (bind.save != save) { @@ -18641,8 +18542,8 @@ InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, b sScriptMgr->OnPlayerBindToInstance(this, save->GetDifficulty(), save->GetMapId(), permanent); return &bind; } - else - return NULL; + + return NULL; } void Player::BindToInstance() @@ -19363,7 +19264,7 @@ void Player::_SaveInventory(SQLTransaction& trans) if (!item || item->GetState() == ITEM_NEW) continue; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY_BY_ITEM); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY_BY_ITEM); stmt->setUInt32(0, item->GetGUIDLow()); trans->Append(stmt); @@ -19448,7 +19349,6 @@ void Player::_SaveInventory(SQLTransaction& trans) } } - PreparedStatement* stmt = NULL; switch (item->GetState()) { case ITEM_NEW: @@ -19555,7 +19455,7 @@ void Player::_SaveMail(SQLTransaction& trans) Mail* m = (*itr); if (m->state == MAIL_STATE_CHANGED) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_MAIL); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_MAIL); stmt->setUInt8(0, uint8(m->HasItems() ? 1 : 0)); stmt->setUInt32(1, uint32(m->expire_time)); stmt->setUInt32(2, uint32(m->deliver_time)); @@ -19582,7 +19482,6 @@ void Player::_SaveMail(SQLTransaction& trans) { if (m->HasItems()) { - PreparedStatement* stmt = NULL; for (MailItemInfoVec::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); @@ -20943,7 +20842,7 @@ void Player::RemovePetitionsAndSigns(uint64 guid, uint32 type) if (type == 10) { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_PETITION_SIGNATURES); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_PETITION_SIGNATURES); stmt->setUInt32(0, GUID_LOPART(guid)); @@ -20951,7 +20850,7 @@ void Player::RemovePetitionsAndSigns(uint64 guid, uint32 type) } else { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PETITION_SIGNATURE); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PETITION_SIGNATURE); stmt->setUInt32(0, GUID_LOPART(guid)); stmt->setUInt8(1, uint8(type)); @@ -21014,7 +20913,7 @@ uint32 Player::GetRBGPersonalRating() const return 0; } -void Player::SetRestBonus (float rest_bonus_new) +void Player::SetRestBonus(float rest_bonus_new) { // Prevent resting on max level if (getLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) @@ -24523,6 +24422,11 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot) UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE, item->itemid, item->count, loot->loot_type); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM, item->itemid, item->count); + + // LootItem is being removed (looted) from the container, delete it from the DB. + if (loot->containerID > 0) + loot->DeleteLootItemFromContainerItemDB(item->itemid); + } else SendEquipError(msg, NULL, NULL, item->itemid); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 4baa17d4377..15628c61e10 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2179,8 +2179,6 @@ class Player : public Unit, public GridObject<Player> void SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool own_team_only); void SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr); - void SendTeleportPacket(Position &oldPos); - Corpse* GetCorpse() const; void SpawnCorpseBones(); void CreateCorpse(); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index e8ac91eb145..ff6c8e4709c 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -5463,37 +5463,14 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // Shadow's Fate (Shadowmourne questline) case 71169: { - target = triggeredByAura->GetCaster(); - if (!target) - return false; - Player* player = target->ToPlayer(); - if (!player) - return false; - // not checking Infusion auras because its in targetAuraSpell of credit spell - if (player->GetQuestStatus(24749) == QUEST_STATUS_INCOMPLETE) // Unholy Infusion - { - if (GetEntry() != 36678) // Professor Putricide - return false; - CastSpell(target, 71518, true); // Quest Credit - return true; - } - else if (player->GetQuestStatus(24756) == QUEST_STATUS_INCOMPLETE) // Blood Infusion - { - if (GetEntry() != 37955) // Blood-Queen Lana'thel - return false; - CastSpell(target, 72934, true); // Quest Credit - return true; - } - else if (player->GetQuestStatus(24757) == QUEST_STATUS_INCOMPLETE) // Frost Infusion + Unit* caster = triggeredByAura->GetCaster(); + if (caster && caster->GetTypeId() == TYPEID_PLAYER && caster->ToPlayer()->GetQuestStatus(24547) == QUEST_STATUS_INCOMPLETE) { - if (GetEntry() != 36853) // Sindragosa - return false; - CastSpell(target, 72289, true); // Quest Credit + CastSpell(caster, 71203, true); return true; } - else if (player->GetQuestStatus(24547) == QUEST_STATUS_INCOMPLETE) // A Feast of Souls - triggered_spell_id = 71203; - break; + else + return false; } // Essence of the Blood Queen case 70871: @@ -8044,34 +8021,44 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg // Shadow's Fate (Shadowmourne questline) case 71169: { - if (GetTypeId() != TYPEID_PLAYER) + // Victim needs more checks so bugs, rats or summons can not be affected by the proc. + if (GetTypeId() != TYPEID_PLAYER || !victim || victim->GetTypeId() != TYPEID_UNIT || victim->GetCreatureType() == CREATURE_TYPE_CRITTER) return false; Player* player = ToPlayer(); - if (player->GetQuestStatus(24749) == QUEST_STATUS_INCOMPLETE) // Unholy Infusion + if (player->GetQuestStatus(24547) == QUEST_STATUS_INCOMPLETE) { - if (!player->HasAura(71516) || victim->GetEntry() != 36678) // Shadow Infusion && Professor Putricide - return false; - } - else if (player->GetQuestStatus(24756) == QUEST_STATUS_INCOMPLETE) // Blood Infusion - { - if (!player->HasAura(72154) || victim->GetEntry() != 37955) // Thirst Quenched && Blood-Queen Lana'thel - return false; + break; } - else if (player->GetQuestStatus(24757) == QUEST_STATUS_INCOMPLETE) // Frost Infusion + else if (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC) { - if (!player->HasAura(72290) || victim->GetEntry() != 36853) // Frost-Imbued Blade && Sindragosa + uint32 spellId = 0; + uint32 questId = 0; + switch (victim->GetEntry()) + { + case 36678: // NPC: Professor Putricide + questId = 24749; // Quest: Unholy Infusion + spellId = 71516; // Spell: Shadow Infusion + break; + case 37955: // NPC: Blood-Queen Lana'thel + questId = 24756; // Quest: Blood Infusion + spellId = 72154; // Spell: Thirst Quenched + break; + case 36853: // NPC: Sindragosa + questId = 24757; // Quest: Frost Infusion + spellId = 72290; // Spell: Frost-Imbued Blade + break; + default: + return false; + } + + if (player->GetQuestStatus(questId) != QUEST_STATUS_INCOMPLETE || !player->HasAura(spellId)) return false; - } - else if (player->GetQuestStatus(24547) != QUEST_STATUS_INCOMPLETE) // A Feast of Souls - return false; - if (victim->GetTypeId() != TYPEID_UNIT) - return false; - // critters are not allowed - if (victim->GetCreatureType() == CREATURE_TYPE_CRITTER) + break; + } + else return false; - break; } } @@ -10863,7 +10850,10 @@ void Unit::CombatStart(Unit* target, bool initialAggro) if (!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER && !target->ToCreature()->HasReactState(REACT_PASSIVE) && target->ToCreature()->IsAIEnabled) { - target->ToCreature()->AI()->AttackStart(this); + if (target->isPet()) + target->ToCreature()->AI()->AttackedBy(this); // PetAI has special handler before AttackStart() + else + target->ToCreature()->AI()->AttackStart(this); } SetInCombatWith(target); @@ -16670,8 +16660,71 @@ void Unit::NearTeleportTo(float x, float y, float z, float orientation, bool cas else { UpdatePosition(x, y, z, orientation, true); - SendMovementFlagUpdate(); + Position pos; // dummy, not used for creatures. + SendTeleportPacket(pos); + } +} + +void Unit::SendTeleportPacket(Position& oldPos) +{ + ObjectGuid guid = GetGUID(); + ObjectGuid transGuid = GetTransGUID(); + + WorldPacket data(MSG_MOVE_TELEPORT, 38); + data.WriteBit(guid[6]); + data.WriteBit(guid[0]); + data.WriteBit(guid[3]); + data.WriteBit(guid[2]); + data.WriteBit(0); // unknown + data.WriteBit(uint64(transGuid)); + data.WriteBit(guid[1]); + if (transGuid) + { + data.WriteBit(transGuid[1]); + data.WriteBit(transGuid[3]); + data.WriteBit(transGuid[2]); + data.WriteBit(transGuid[5]); + data.WriteBit(transGuid[0]); + data.WriteBit(transGuid[7]); + data.WriteBit(transGuid[6]); + data.WriteBit(transGuid[4]); + } + + data.WriteBit(guid[4]); + data.WriteBit(guid[7]); + data.WriteBit(guid[5]); + data.FlushBits(); + + if (transGuid) + { + data.WriteByteSeq(transGuid[6]); + data.WriteByteSeq(transGuid[5]); + data.WriteByteSeq(transGuid[1]); + data.WriteByteSeq(transGuid[7]); + data.WriteByteSeq(transGuid[0]); + data.WriteByteSeq(transGuid[2]); + data.WriteByteSeq(transGuid[4]); + data.WriteByteSeq(transGuid[3]); } + + data << uint32(0); // counter + data.WriteByteSeq(guid[1]); + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[5]); + data << float(GetPositionX()); + data.WriteByteSeq(guid[4]); + data << float(GetOrientation()); + data.WriteByteSeq(guid[7]); + data << float(GetPositionZMinusOffset()); + data.WriteByteSeq(guid[0]); + data.WriteByteSeq(guid[6]); + data << float(GetPositionY()); + + if (GetTypeId == TYPEID_PLAYER) + Relocate(&oldPos); + + SendMessageToSet(&data, false); } bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool teleport) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 515e7644299..c00fa03a4ea 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1581,6 +1581,7 @@ class Unit : public WorldObject void SendSpellDamageImmune(Unit* target, uint32 spellId); void NearTeleportTo(float x, float y, float z, float orientation, bool casting = false); + void SendTeleportPacket(Position& oldPos); virtual bool UpdatePosition(float x, float y, float z, float ang, bool teleport = false); // returns true if unit's position really changed bool UpdatePosition(const Position &pos, bool teleport = false) { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); } diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 06368f6924e..dadbce26816 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1900,7 +1900,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) if (recvData.GetOpcode() == CMSG_CHAR_FACTION_CHANGE) { // Delete all Flypaths - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TAXI_PATH); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TAXI_PATH); stmt->setUInt32(0, lowGuid); trans->Append(stmt); @@ -1945,7 +1945,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) taximaskstream << '0'; std::string taximask = taximaskstream.str(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TAXIMASK); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TAXIMASK); stmt->setString(0, taximask); stmt->setUInt32(1, lowGuid); trans->Append(stmt); @@ -1992,7 +1992,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) { // Reset guild - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER); stmt->setUInt32(0, lowGuid); @@ -2005,7 +2005,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND)) { // Delete Friend List - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID); stmt->setUInt32(0, lowGuid); trans->Append(stmt); @@ -2051,7 +2051,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) uint32 achiev_alliance = it->first; uint32 achiev_horde = it->second; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT); stmt->setUInt16(0, uint16(team == TEAM_ALLIANCE ? achiev_alliance : achiev_horde)); stmt->setUInt32(1, lowGuid); trans->Append(stmt); @@ -2069,7 +2069,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) uint32 item_alliance = it->first; uint32 item_horde = it->second; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_INVENTORY_FACTION_CHANGE); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_INVENTORY_FACTION_CHANGE); stmt->setUInt32(0, (team == TEAM_ALLIANCE ? item_alliance : item_horde)); stmt->setUInt32(1, (team == TEAM_ALLIANCE ? item_horde : item_alliance)); stmt->setUInt32(2, guid); @@ -2082,7 +2082,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) uint32 spell_alliance = it->first; uint32 spell_horde = it->second; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_BY_SPELL); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_BY_SPELL); stmt->setUInt32(0, (team == TEAM_ALLIANCE ? spell_alliance : spell_horde)); stmt->setUInt32(1, lowGuid); trans->Append(stmt); @@ -2103,7 +2103,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) uint32 oldReputation = (team == TEAM_ALLIANCE) ? reputation_horde : reputation_alliance; // select old standing set in db - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_REP_BY_FACTION); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_REP_BY_FACTION); stmt->setUInt32(0, oldReputation); stmt->setUInt32(1, lowGuid); PreparedQueryResult result = CharacterDatabase.Query(stmt); @@ -2195,7 +2195,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) for (uint32 index = 0; index < ktcount; ++index) ss << knownTitles[index] << ' '; - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TITLES_FACTION_CHANGE); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TITLES_FACTION_CHANGE); stmt->setString(0, ss.str().c_str()); stmt->setUInt32(1, lowGuid); trans->Append(stmt); diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index e34dde7209f..1de64351876 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -94,6 +94,10 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData) } player->StoreLootItem(lootSlot, loot); + + // If player is removing the last LootItem, delete the empty container. + if (loot->isLooted() && IS_ITEM_GUID(lguid)) + player->GetSession()->DoLootRelease(lguid); } void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/) @@ -209,6 +213,14 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/) } loot->gold = 0; + + // Delete the money loot record from the DB + if (loot->containerID > 0) + loot->DeleteLootMoneyFromContainerItemDB(); + + // Delete container if empty + if (loot->isLooted() && IS_ITEM_GUID(guid)) + player->GetSession()->DoLootRelease(guid); } } @@ -390,8 +402,10 @@ void WorldSession::DoLootRelease(uint64 lguid) player->DestroyItemCount(pItem, count, true); } else - // FIXME: item must not be deleted in case not fully looted state. But this pre-request implement loot saving in DB at item save. Or cheating possible. - player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); + { + if (pItem->loot.isLooted()) // Only delete item if no loot or money (unlooted loot is saved to db) + player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); + } return; // item can be looted only single player } else diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 68f6626b3b1..62fd1a416d9 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -334,6 +334,7 @@ LootItem::LootItem(LootStoreItem const& li) is_blocked = 0; is_underthreshold = 0; is_counted = 0; + canSave = true; } // Basic checks for player/item compatibility - if false no chance to see the item in the loot @@ -654,6 +655,33 @@ void Loot::generateMoneyLoot(uint32 minAmount, uint32 maxAmount) } } +void Loot::DeleteLootItemFromContainerItemDB(uint32 itemID) +{ + // Deletes a single item associated with an openable item from the DB + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM); + stmt->setUInt32(0, containerID); + stmt->setUInt32(1, itemID); + CharacterDatabase.Execute(stmt); + + // Mark the item looted to prevent resaving + for (LootItemList::iterator _itr = items.begin(); _itr != items.end(); _itr++) + { + if (!_itr->itemid == itemID) + continue; + + _itr->canSave = true; + break; + } +} + +void Loot::DeleteLootMoneyFromContainerItemDB() +{ + // Deletes money loot associated with an openable item from the DB + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY); + stmt->setUInt32(0, containerID); + CharacterDatabase.Execute(stmt); +} + LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem* *qitem, QuestItem* *ffaitem, QuestItem* *conditem) { LootItem* item = NULL; @@ -1243,6 +1271,19 @@ void LootTemplate::CopyConditions(ConditionList conditions) i->CopyConditions(conditions); } +void LootTemplate::CopyConditions(LootItem* li) const +{ + // Copies the conditions list from a template item to a LootItem + for (LootStoreItemList::const_iterator _iter = Entries.begin(); _iter != Entries.end(); ++_iter) + { + if (!_iter->itemid == li->itemid) + continue; + + li->conditions = _iter->conditions; + break; + } +} + // Rolls for every item in the template and adds the rolled items the the loot void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId) const { diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index 72243cd98f6..e7824f61f92 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -140,14 +140,17 @@ struct LootItem bool is_counted : 1; bool needs_quest : 1; // quest drop bool follow_loot_rules : 1; + bool canSave; // Constructor, copies most fields from LootStoreItem, generates random count and random suffixes/properties // Should be called for non-reference LootStoreItem entries only (mincountOrRef > 0) explicit LootItem(LootStoreItem const& li); + // Empty constructor for creating an empty LootItem to be filled in with DB data + LootItem() : canSave(true){}; + // Basic checks for player/item compatibility - if false no chance to see the item in the loot bool AllowedForPlayer(Player const* player) const; - void AddAllowedLooter(Player const* player); const AllowedLooterSet & GetAllowedLooters() const { return allowedGUIDs; } }; @@ -222,6 +225,7 @@ class LootTemplate // Rolls for every item in the template and adds the rolled items the the loot void Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId = 0) const; void CopyConditions(ConditionList conditions); + void CopyConditions(LootItem* li) const; // True if template includes at least 1 quest drop entry bool HasQuestDrop(LootTemplateMap const& store, uint8 groupId = 0) const; @@ -286,9 +290,17 @@ struct Loot uint64 roundRobinPlayer; // GUID of the player having the Round-Robin ownership for the loot. If 0, round robin owner has released. LootType loot_type; // required for achievement system - Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), loot_type(LOOT_CORPSE) {} + // GUIDLow of container that holds this loot (item_instance.entry) + // Only set for inventory items that can be right-click looted + uint32 containerID; + + Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), loot_type(LOOT_CORPSE), containerID(0) {} ~Loot() { clear(); } + // For deleting items at loot removal since there is no backward interface to the Item() + void DeleteLootItemFromContainerItemDB(uint32 itemID); + void DeleteLootMoneyFromContainerItemDB(); + // if loot becomes invalid this reference is used to inform the listener void addLootValidatorRef(LootValidatorRef* pLootValidatorRef) { diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 9e149903199..a9f2b283a40 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2475,7 +2475,7 @@ bool InstanceMap::AddPlayerToMap(Player* player) if (uint32 dungeonId = sLFGMgr->GetDungeon(group->GetGUID(), true)) if (LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId)) if (LFGDungeonData const* randomDungeon = sLFGMgr->GetLFGDungeon(*(sLFGMgr->GetSelectedDungeons(player->GetGUID()).begin()))) - if (uint32(dungeon->map) == GetId() && dungeon->difficulty == uint32(GetDifficulty()) && randomDungeon->type == uint32(LFG_TYPE_RANDOM)) + if (uint32(dungeon->map) == GetId() && dungeon->difficulty == GetDifficulty() && randomDungeon->type == LFG_TYPE_RANDOM) player->CastSpell(player, LFG_SPELL_LUCK_OF_THE_DRAW, true); } diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 21732bad951..0f9962f58df 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -5372,7 +5372,7 @@ void AuraEffect::HandleAuraLinked(AuraApplication const* aurApp, uint8 mode, boo { Unit* target = aurApp->GetTarget(); - uint32 triggeredSpellId = m_spellInfo->Effects[m_effIndex].TriggerSpell; + uint32 triggeredSpellId = sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->Effects[m_effIndex].TriggerSpell, target); SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggeredSpellId); if (!triggeredSpellInfo) return; diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 9b9b888a9f3..e8d0cb6feeb 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1680,11 +1680,21 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta if (unitTarget->HasUnitState(UNIT_STATE_IN_FLIGHT)) return SPELL_FAILED_BAD_TARGETS; - if (TargetAuraState && !unitTarget->HasAuraState(AuraStateType(TargetAuraState), this, caster)) - return SPELL_FAILED_TARGET_AURASTATE; + /* TARGET_UNIT_MASTER gets blocked here for passengers, because the whole idea of this check is to + not allow passengers to be implicitly hit by spells, however this target type should be an exception, + if this is left it kills spells that award kill credit from vehicle to master (few spells), + the use of these 2 covers passenger target check, logically, if vehicle cast this to master it should always hit + him, because it would be it's passenger, there's no such case where this gets to fail legitimacy, this problem + cannot be solved from within the check in other way since target type cannot be called for the spell currently + Spell examples: [ID - 52864 Devour Water, ID - 52862 Devour Wind, ID - 49370 Wyrmrest Defender: Destabilize Azure Dragonshrine Effect] */ + if (!caster->IsVehicle() && !(caster->GetCharmerOrOwner() == target)) + { + if (TargetAuraState && !unitTarget->HasAuraState(AuraStateType(TargetAuraState), this, caster)) + return SPELL_FAILED_TARGET_AURASTATE; - if (TargetAuraStateNot && unitTarget->HasAuraState(AuraStateType(TargetAuraStateNot), this, caster)) - return SPELL_FAILED_TARGET_AURASTATE; + if (TargetAuraStateNot && unitTarget->HasAuraState(AuraStateType(TargetAuraStateNot), this, caster)) + return SPELL_FAILED_TARGET_AURASTATE; + } if (TargetAuraSpell && !unitTarget->HasAura(sSpellMgr->GetSpellIdForDifficulty(TargetAuraSpell, caster))) return SPELL_FAILED_TARGET_AURASTATE; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 308ac07f404..38570022cdf 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3442,6 +3442,9 @@ void SpellMgr::LoadDbcDataCorrections() case 71123: // Decimate (Stinky & Precious) spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_100_YARDS; // 100yd break; + case 71169: // Shadow's Fate + spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS; + break; case 72378: // Blood Nova (Deathbringer Saurfang) case 73058: // Blood Nova (Deathbringer Saurfang) spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; diff --git a/src/server/game/Tools/PlayerDump.cpp b/src/server/game/Tools/PlayerDump.cpp index 7e3ac8b319d..a8ed3207db5 100644 --- a/src/server/game/Tools/PlayerDump.cpp +++ b/src/server/game/Tools/PlayerDump.cpp @@ -411,7 +411,6 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s if (!fin) return DUMP_FILE_OPEN_ERROR; - QueryResult result = QueryResult(NULL); char newguid[20], chraccount[20], newpetid[20], currpetid[20], lastpetid[20]; // make sure the same guid doesn't already exist and is safe to use |
