diff options
Diffstat (limited to 'src')
29 files changed, 618 insertions, 325 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 diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp index 0f575043da6..14ea31a6518 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp @@ -31,10 +31,10 @@ enum Spells SPELL_REJOIN_VISCIDUS = 25896, SPELL_VISCIDUS_EXPLODE = 25938, SPELL_VISCIDUS_SUICIDE = 26003, + SPELL_VISCIDUS_SHRINKS = 25893, // Removed from client, in world.spell_dbc SPELL_MEMBRANE_VISCIDUS = 25994, // damage reduction spell - removed from DBC SPELL_VISCIDUS_WEAKNESS = 25926, // aura which procs at damage - should trigger the slow spells - removed from DBC - SPELL_VISCIDUS_SHRINKS = 25893, // (6) Apply Aura #61: Mod Scale Value: -4 - removed from DBC SPELL_VISCIDUS_GROWS = 25897, // removed from DBC SPELL_SUMMON_GLOBS = 25885, // summons npc 15667 using spells from 25865 to 25884; All spells have target coords - removed from DBC SPELL_VISCIDUS_TELEPORT = 25904, // removed from DBC @@ -54,19 +54,26 @@ enum Phases PHASE_GLOB = 3 }; -enum HitCounter +enum Emotes { - HITCOUNTER_SLOW = 100, // "Viscidus begins to slow." - HITCOUNTER_SLOW_MORE = 150, // "Viscidus begins to freeze." - HITCOUNTER_FREEZE = 200, // "Viscidus is frozen solid." + EMOTE_SLOW = 0, + EMOTE_FREEZE = 1, + EMOTE_FROZEN = 2, - // 4.3.4 data - HITCOUNTER_CRACK = 50, // "Viscidus begins to crack." - HITCOUNTER_SHATTER = 100, // "Viscidus looks ready to shatter." - HITCOUNTER_EXPLODE = 150, // "Viscidus explodes." + EMOTE_CRACK = 3, + EMOTE_SHATTER = 4, + EMOTE_EXPLODE = 5 +}; - // 1.12 data - // HITCOUNTER_EXPLODE = 75 +enum HitCounter +{ + HITCOUNTER_SLOW = 100, + HITCOUNTER_SLOW_MORE = 150, + HITCOUNTER_FREEZE = 200, + + HITCOUNTER_CRACK = 50, + HITCOUNTER_SHATTER = 100, + HITCOUNTER_EXPLODE = 150, }; enum MovePoints @@ -74,7 +81,7 @@ enum MovePoints ROOM_CENTER = 1 }; -Position const ViscidusCoord = { -7992.36f, 908.19f, -52.62f, 1.68f }; // TODO: Visci ain't room middle +Position const ViscidusCoord = { -7992.36f, 908.19f, -52.62f, 1.68f }; // TODO: Visci isn't in room middle float const RoomRadius = 40.0f; // TODO: Not sure if its correct class boss_viscidus : public CreatureScript @@ -102,6 +109,7 @@ class boss_viscidus : public CreatureScript if (attacker->HasUnitState(UNIT_STATE_MELEE_ATTACKING) && _hitcounter >= HITCOUNTER_EXPLODE) { + Talk(EMOTE_EXPLODE); events.Reset(); _phase = PHASE_GLOB; DoCast(me, SPELL_VISCIDUS_EXPLODE); @@ -125,6 +133,10 @@ class boss_viscidus : public CreatureScript } } } + else if (_hitcounter == HITCOUNTER_SHATTER) + Talk(EMOTE_SHATTER); + else if (_hitcounter == HITCOUNTER_CRACK) + Talk(EMOTE_CRACK); } void SpellHit(Unit* /*caster*/, SpellInfo const* spell) @@ -135,6 +147,8 @@ class boss_viscidus : public CreatureScript if (_hitcounter >= HITCOUNTER_FREEZE) { + _hitcounter = 0; + Talk(EMOTE_FROZEN); _phase = PHASE_MELEE; DoCast(me, SPELL_VISCIDUS_FREEZE); me->RemoveAura(SPELL_VISCIDUS_SLOWED_MORE); @@ -142,11 +156,15 @@ class boss_viscidus : public CreatureScript } else if (_hitcounter >= HITCOUNTER_SLOW_MORE) { + Talk(EMOTE_FREEZE); me->RemoveAura(SPELL_VISCIDUS_SLOWED); DoCast(me, SPELL_VISCIDUS_SLOWED_MORE); } else if (_hitcounter >= HITCOUNTER_SLOW) + { + Talk(EMOTE_SLOW); DoCast(me, SPELL_VISCIDUS_SLOWED); + } } } @@ -183,6 +201,7 @@ class boss_viscidus : public CreatureScript if (_phase == PHASE_GLOB && summons.empty()) { + DoResetThreat(); me->NearTeleportTo(ViscidusCoord.GetPositionX(), ViscidusCoord.GetPositionY(), ViscidusCoord.GetPositionZ(), @@ -260,7 +279,7 @@ class npc_glob_of_viscidus : public CreatureScript else { Viscidus->SetHealth(Viscidus->GetHealth() - Viscidus->GetMaxHealth() / 20); - Viscidus->SetObjectScale(Viscidus->GetFloatValue(OBJECT_FIELD_SCALE_X) - 0.05f); // TODO: Not sure if blizzlike + Viscidus->GetAI()->DoCast(Viscidus, SPELL_VISCIDUS_SHRINKS); } } } diff --git a/src/server/scripts/Kalimdor/moonglade.cpp b/src/server/scripts/Kalimdor/moonglade.cpp index bea556bdfa6..bcf67271179 100644 --- a/src/server/scripts/Kalimdor/moonglade.cpp +++ b/src/server/scripts/Kalimdor/moonglade.cpp @@ -319,7 +319,7 @@ public: } void IsSummonedBy(Unit* /*summoner*/) - { + { std::list<Player*> playerOnQuestList; Trinity::AnyPlayerInObjectRangeCheck checker(me, 5.0f); Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(me, playerOnQuestList, checker); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp index 2b240bc93d8..a246852c8ed 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp @@ -62,6 +62,9 @@ enum Spells SPELL_INCITE_TERROR = 73070, SPELL_BLOODBOLT_WHIRL = 71772, SPELL_ANNIHILATE = 71322, + + // Blood Infusion + SPELL_BLOOD_INFUSION_CREDIT = 72934 }; enum Shadowmourne @@ -182,6 +185,10 @@ class boss_blood_queen_lana_thel : public CreatureScript { _JustDied(); Talk(SAY_DEATH); + + if (Is25ManRaid() && me->HasAura(SPELL_SHADOWS_FATE)) + DoCastAOE(SPELL_BLOOD_INFUSION_CREDIT, true); + CleanAuras(); // Blah, credit the quest if (_creditBloodQuickening) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index 71264be564b..8fc37e9f7da 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -1218,6 +1218,12 @@ class spell_deathbringer_blood_nova_targeting : public SpellScriptLoader if (targetsAtRange < minTargets) targetsAtRange = std::min<uint32>(targets.size() - 1, minTargets); + if (!targetsAtRange) + { + targets.clear(); + return; + } + std::list<WorldObject*>::const_iterator itr = targets.begin(); std::advance(itr, urand(0, targetsAtRange)); target = *itr; @@ -1228,10 +1234,10 @@ class spell_deathbringer_blood_nova_targeting : public SpellScriptLoader // use the same target for first and second effect void FilterTargetsSubsequent(std::list<WorldObject*>& unitList) { + unitList.clear(); if (!target) return; - unitList.clear(); unitList.push_back(target); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 4727504a4bd..d697be214c7 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -51,62 +51,65 @@ enum ScriptTexts enum Spells { // Festergut - SPELL_RELEASE_GAS_VISUAL = 69125, - SPELL_GASEOUS_BLIGHT_LARGE = 69157, - SPELL_GASEOUS_BLIGHT_MEDIUM = 69162, - SPELL_GASEOUS_BLIGHT_SMALL = 69164, - SPELL_MALLABLE_GOO_H = 70852, + SPELL_RELEASE_GAS_VISUAL = 69125, + SPELL_GASEOUS_BLIGHT_LARGE = 69157, + SPELL_GASEOUS_BLIGHT_MEDIUM = 69162, + SPELL_GASEOUS_BLIGHT_SMALL = 69164, + SPELL_MALLABLE_GOO_H = 70852, // Rotface - SPELL_VILE_GAS_H = 69240, + SPELL_VILE_GAS_H = 69240, // Professor Putricide - SPELL_SLIME_PUDDLE_TRIGGER = 70341, - SPELL_MALLEABLE_GOO = 70852, - SPELL_UNSTABLE_EXPERIMENT = 70351, - SPELL_TEAR_GAS = 71617, // phase transition - SPELL_TEAR_GAS_CREATURE = 71618, - SPELL_TEAR_GAS_CANCEL = 71620, - SPELL_TEAR_GAS_PERIODIC_TRIGGER = 73170, - SPELL_CREATE_CONCOCTION = 71621, - SPELL_GUZZLE_POTIONS = 71893, - SPELL_OOZE_TANK_PROTECTION = 71770, // protects the tank - SPELL_CHOKING_GAS_BOMB = 71255, - SPELL_OOZE_VARIABLE = 74118, - SPELL_GAS_VARIABLE = 74119, - SPELL_UNBOUND_PLAGUE = 70911, - SPELL_UNBOUND_PLAGUE_SEARCHER = 70917, - SPELL_PLAGUE_SICKNESS = 70953, - SPELL_UNBOUND_PLAGUE_PROTECTION = 70955, - SPELL_MUTATED_PLAGUE = 72451, - SPELL_MUTATED_PLAGUE_CLEAR = 72618, + SPELL_SLIME_PUDDLE_TRIGGER = 70341, + SPELL_MALLEABLE_GOO = 70852, + SPELL_UNSTABLE_EXPERIMENT = 70351, + SPELL_TEAR_GAS = 71617, // phase transition + SPELL_TEAR_GAS_CREATURE = 71618, + SPELL_TEAR_GAS_CANCEL = 71620, + SPELL_TEAR_GAS_PERIODIC_TRIGGER = 73170, + SPELL_CREATE_CONCOCTION = 71621, + SPELL_GUZZLE_POTIONS = 71893, + SPELL_OOZE_TANK_PROTECTION = 71770, // protects the tank + SPELL_CHOKING_GAS_BOMB = 71255, + SPELL_OOZE_VARIABLE = 74118, + SPELL_GAS_VARIABLE = 74119, + SPELL_UNBOUND_PLAGUE = 70911, + SPELL_UNBOUND_PLAGUE_SEARCHER = 70917, + SPELL_PLAGUE_SICKNESS = 70953, + SPELL_UNBOUND_PLAGUE_PROTECTION = 70955, + SPELL_MUTATED_PLAGUE = 72451, + SPELL_MUTATED_PLAGUE_CLEAR = 72618, // Slime Puddle - SPELL_GROW_STACKER = 70345, - SPELL_GROW = 70347, - SPELL_SLIME_PUDDLE_AURA = 70343, + SPELL_GROW_STACKER = 70345, + SPELL_GROW = 70347, + SPELL_SLIME_PUDDLE_AURA = 70343, // Gas Cloud - SPELL_GASEOUS_BLOAT_PROC = 70215, - SPELL_GASEOUS_BLOAT = 70672, - SPELL_GASEOUS_BLOAT_PROTECTION = 70812, - SPELL_EXPUNGED_GAS = 70701, + SPELL_GASEOUS_BLOAT_PROC = 70215, + SPELL_GASEOUS_BLOAT = 70672, + SPELL_GASEOUS_BLOAT_PROTECTION = 70812, + SPELL_EXPUNGED_GAS = 70701, // Volatile Ooze - SPELL_OOZE_ERUPTION = 70492, - SPELL_VOLATILE_OOZE_ADHESIVE = 70447, - SPELL_OOZE_ERUPTION_SEARCH_PERIODIC = 70457, - SPELL_VOLATILE_OOZE_PROTECTION = 70530, + SPELL_OOZE_ERUPTION = 70492, + SPELL_VOLATILE_OOZE_ADHESIVE = 70447, + SPELL_OOZE_ERUPTION_SEARCH_PERIODIC = 70457, + SPELL_VOLATILE_OOZE_PROTECTION = 70530, // Choking Gas Bomb - SPELL_CHOKING_GAS_BOMB_PERIODIC = 71259, - SPELL_CHOKING_GAS_EXPLOSION_TRIGGER = 71280, + SPELL_CHOKING_GAS_BOMB_PERIODIC = 71259, + SPELL_CHOKING_GAS_EXPLOSION_TRIGGER = 71280, // Mutated Abomination vehicle - SPELL_ABOMINATION_VEHICLE_POWER_DRAIN = 70385, - SPELL_MUTATED_TRANSFORMATION = 70311, - SPELL_MUTATED_TRANSFORMATION_DAMAGE = 70405, - SPELL_MUTATED_TRANSFORMATION_NAME = 72401, + SPELL_ABOMINATION_VEHICLE_POWER_DRAIN = 70385, + SPELL_MUTATED_TRANSFORMATION = 70311, + SPELL_MUTATED_TRANSFORMATION_DAMAGE = 70405, + SPELL_MUTATED_TRANSFORMATION_NAME = 72401, + + // Unholy Infusion + SPELL_UNHOLY_INFUSION_CREDIT = 71518 }; #define SPELL_GASEOUS_BLOAT_HELPER RAID_MODE<uint32>(70672, 72455, 72832, 72833) @@ -293,6 +296,10 @@ class boss_professor_putricide : public CreatureScript { _JustDied(); Talk(SAY_DEATH); + + if (Is25ManRaid() && me->HasAura(SPELL_SHADOWS_FATE)) + DoCastAOE(SPELL_UNHOLY_INFUSION_CREDIT, true); + DoCast(SPELL_MUTATED_PLAGUE_CLEAR); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index 96cabfed918..8bdef30a711 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -82,6 +82,9 @@ enum Spells SPELL_FOCUS_FIRE = 71350, SPELL_ORDER_WHELP = 71357, SPELL_CONCUSSIVE_SHOCK = 71337, + + // Frost Infusion + SPELL_FROST_INFUSION_CREDIT = 72289 }; enum Events @@ -231,8 +234,12 @@ class boss_sindragosa : public CreatureScript void JustDied(Unit* killer) { - BossAI::JustDied(killer); + _JustDied(); Talk(SAY_DEATH); + + if (Is25ManRaid() && me->HasAura(SPELL_SHADOWS_FATE)) + DoCastAOE(SPELL_FROST_INFUSION_CREDIT, true); + } void EnterCombat(Unit* victim) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h index 4e117d9f3e3..8edaf1aa985 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h @@ -54,6 +54,9 @@ enum SharedSpells // The Lich King SPELL_ARTHAS_TELEPORTER_CEREMONY = 72915, SPELL_FROSTMOURNE_TELEPORT_VISUAL = 73078, + + // Shadowmourne questline + SPELL_SHADOWS_FATE = 71169 }; enum TeleporterSpells diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp index 8f68542d462..c8789d680ed 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp @@ -208,7 +208,7 @@ class boss_ignis : public CreatureScript switch (eventId) { case EVENT_JET: - me->MonsterTextEmote(EMOTE_JETS, 0, true); + Talk(EMOTE_JETS); DoCast(me, SPELL_FLAME_JETS); events.ScheduleEvent(EVENT_JET, urand(35000, 40000)); break; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp index 9643b2ec9ab..5f560ed8dd4 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -1084,7 +1084,7 @@ class achievement_quick_shave : public AchievementCriteriaScript bool OnCheck(Player* /*source*/, Unit* target) { - if (target) + if (target) if (Creature* razorscale = target->ToCreature()) if (razorscale->AI()->GetData(DATA_QUICK_SHAVE)) return true; diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index c8ae44d9cd9..c8f3236a008 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1418,7 +1418,7 @@ class spell_gen_luck_of_the_draw : public SpellScriptLoader if (group->isLFGGroup()) if (uint32 dungeonId = sLFGMgr->GetDungeon(group->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()) if (randomDungeon && randomDungeon->type == LFG_TYPE_RANDOM) return; // in correct dungeon diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 765bb97bf64..0b8048aeb2c 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -571,6 +571,15 @@ void CharacterDatabaseConnection::DoPrepareStatements() PREPARE_STATEMENT(CHAR_REP_GUILD_FINDER_GUILD_SETTINGS, "REPLACE INTO guild_finder_guild_settings (guildId, availability, classRoles, interests, level, listed, comment) VALUES(?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PREPARE_STATEMENT(CHAR_DEL_GUILD_FINDER_GUILD_SETTINGS, "DELETE FROM guild_finder_guild_settings WHERE guildId = ?", CONNECTION_ASYNC); + // Items that hold loot or money + PREPARE_STATEMENT(CHAR_SEL_ITEMCONTAINER_ITEMS, "SELECT item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix FROM item_loot_items WHERE container_id = ?", CONNECTION_SYNCH); + PREPARE_STATEMENT(CHAR_DEL_ITEMCONTAINER_ITEMS, "DELETE FROM item_loot_items WHERE container_id = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_ITEMCONTAINER_ITEM, "DELETE FROM item_loot_items WHERE container_id = ? AND item_id = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_INS_ITEMCONTAINER_ITEMS, "INSERT INTO item_loot_items (container_id, item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_SEL_ITEMCONTAINER_MONEY, "SELECT money FROM item_loot_money WHERE container_id = ?", CONNECTION_SYNCH); + PREPARE_STATEMENT(CHAR_DEL_ITEMCONTAINER_MONEY, "DELETE FROM item_loot_money WHERE container_id = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_INS_ITEMCONTAINER_MONEY, "INSERT INTO item_loot_money (container_id, money) VALUES (?, ?)", CONNECTION_ASYNC); + // Calendar PREPARE_STATEMENT(CHAR_REP_CALENDAR_EVENT, "REPLACE INTO calendar_events (id, creator, title, description, type, dungeon, eventtime, flags, time2) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PREPARE_STATEMENT(CHAR_DEL_CALENDAR_EVENT, "DELETE FROM calendar_events WHERE id = ?", CONNECTION_ASYNC); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index a1ff27ce507..0f04808cbcf 100755 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -531,6 +531,14 @@ enum CharacterDatabaseStatements CHAR_REP_CALENDAR_INVITE, CHAR_DEL_CALENDAR_INVITE, + CHAR_SEL_ITEMCONTAINER_ITEMS, + CHAR_DEL_ITEMCONTAINER_ITEMS, + CHAR_DEL_ITEMCONTAINER_ITEM, + CHAR_INS_ITEMCONTAINER_ITEMS, + CHAR_SEL_ITEMCONTAINER_MONEY, + CHAR_DEL_ITEMCONTAINER_MONEY, + CHAR_INS_ITEMCONTAINER_MONEY, + MAX_CHARACTERDATABASE_STATEMENTS }; |