diff options
Diffstat (limited to 'src/game/Player.cpp')
-rw-r--r-- | src/game/Player.cpp | 229 |
1 files changed, 164 insertions, 65 deletions
diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 985908dff0a..46906a03e94 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -758,16 +758,10 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8 uint32 item_id = oEntry->ItemId[j]; - // Hack for not existed item id in dbc 3.0.3 - if(item_id==40582) - continue; - + // just skip, reported in ObjectMgr::LoadItemPrototypes ItemPrototype const* iProto = objmgr.GetItemPrototype(item_id); - if(!iProto) - { - sLog.outErrorDb("Initial item id %u (race %u class %u) from CharStartOutfit.dbc not listed in `item_template`, ignoring.",item_id,getRace(),getClass()); + if (!iProto) continue; - } // BuyCount by default uint32 count = iProto->BuyCount; @@ -787,6 +781,11 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8 if(iProto->Stackable < count) count = iProto->Stackable; } + // special amount for daggers + else if(iProto->Class==ITEM_CLASS_WEAPON && iProto->SubClass==ITEM_SUBCLASS_WEAPON_DAGGER) + { + count = 2; // will placed to 2 slots + } StoreNewItemInBestSlots(item_id, count); } @@ -1539,7 +1538,8 @@ bool Player::BuildEnumData( QueryResult_AutoPtr result, WorldPacket * p_data ) *p_data << uint32(char_flags); // character flags // character customize flags *p_data << uint32(atLoginFlags & AT_LOGIN_CUSTOMIZE ? CHAR_CUSTOMIZE_FLAG_CUSTOMIZE : CHAR_CUSTOMIZE_FLAG_NONE); - *p_data << uint8(1); // unknown + // First login + *p_data << uint8(atLoginFlags & AT_LOGIN_FIRST ? 1 : 0); // Pets info { @@ -2074,6 +2074,10 @@ void Player::Regenerate(Powers power) { bool recentCast = IsUnderLastManaUseEffect(); float ManaIncreaseRate = sWorld.getRate(RATE_POWER_MANA); + + if (getLevel() < 15) + ManaIncreaseRate = sWorld.getRate(RATE_POWER_MANA) * (2.066f - (getLevel() * 0.066f)); + if (recentCast) // Trinity Updates Mana in intervals of 2s, which is correct addvalue += GetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER) * ManaIncreaseRate * 0.001f * m_regenTimer; else @@ -2175,6 +2179,9 @@ void Player::RegenerateHealth() float HealthIncreaseRate = sWorld.getRate(RATE_HEALTH); + if (getLevel() < 15) + HealthIncreaseRate = sWorld.getRate(RATE_HEALTH) * (2.066f - (getLevel() * 0.066f)); + float addvalue = 0.0f; // polymorphed case @@ -2497,7 +2504,7 @@ void Player::GiveXP(uint32 xp, Unit* victim) return; // XP resting bonus for kill - uint32 rested_bonus_xp = victim ? GetXPRestBonus(xp) : 0; + uint32 rested_bonus_xp = victim ? GetXPRestBonus(xp) : 0; // Heirloom Experience Bonus float heirloomModifier = 1.0f; @@ -3991,7 +3998,7 @@ void Player::InitVisibleBits() updateVisualBits.SetBit(UNIT_NPC_FLAGS); // PLAYER_QUEST_LOG_x also visible bit on official (but only on party/raid)... - for (uint16 i = PLAYER_QUEST_LOG_1_1; i < PLAYER_QUEST_LOG_25_2; i += 4) + for (uint16 i = PLAYER_QUEST_LOG_1_1; i < PLAYER_QUEST_LOG_25_2; i += MAX_QUEST_OFFSET) updateVisualBits.SetBit(i); // Players visible items are not inventory stuff @@ -4100,7 +4107,7 @@ TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell { if (!trainer_spell->learnedSpell[i]) continue; - + if(!HasSpell(trainer_spell->learnedSpell[i])) { hasSpell = false; @@ -6294,13 +6301,38 @@ void Player::RewardReputation(Quest const *pQuest) // quest reputation reward/loss for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) { - if(pQuest->RewRepFaction[i] && pQuest->RewRepValue[i] ) + if (!pQuest->RewRepFaction[i]) + continue; + if (pQuest->RewRepValue[i]) { int32 rep = CalculateReputationGain(GetQuestLevel(pQuest), pQuest->RewRepValue[i], pQuest->RewRepFaction[i], true); - FactionEntry const* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i]); - if(factionEntry) + if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i])) GetReputationMgr().ModifyReputation(factionEntry, rep); } + else + { + uint32 row = 1; + int32 field = 0; + + if (pQuest->RewRepValueId[i] < 0) + { + ++row; + field = abs(pQuest->RewRepValueId[i]); + } + else + field = pQuest->RewRepValueId[i]; + if (const QuestFactionRewEntry *pRow = sQuestFactionRewardStore.LookupEntry(row)) + { + int32 repPoints = pRow->QuestRewFactionValue[field]; + + if (!repPoints) + continue; + + repPoints = CalculateReputationGain(GetQuestLevel(pQuest), repPoints, pQuest->RewRepFaction[i], true); + if (const FactionEntry* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i])) + GetReputationMgr().ModifyReputation(factionEntry, repPoints); + } + } } // TODO: implement reputation spillover @@ -6817,7 +6849,7 @@ void Player::DuelComplete(DuelCompleteType type) duel->opponent->AttackStop(); } break; - case DUEL_WON: + case DUEL_WON: GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL, 1); if (duel->opponent) { @@ -6895,37 +6927,32 @@ void Player::_ApplyItemMods(Item *item, uint8 slot,bool apply) if (!proto) return; - // not apply mods for broken item - if (item->IsBroken()) - { - if (proto->Socket[0].Color) - CorrectMetaGemEnchants(slot, apply); + if (proto->Socket[0].Color) //only (un)equipping of items with sockets can influence metagems, so no need to waste time with normal items + CorrectMetaGemEnchants(slot, apply); + // not apply/remove mods for broken item + if (item->IsBroken()) return; - } sLog.outDetail("applying mods for item %u ",item->GetGUIDLow()); uint8 attacktype = Player::GetAttackBySlot(slot); - //check disarm only on mod apply to allow remove item mods + // check disarm only on mod apply to allow remove item mods if (!CanUseAttackType(attacktype) ) return; - if(attacktype < MAX_ATTACK) + if (attacktype < MAX_ATTACK) _ApplyWeaponDependentAuraMods(item,WeaponAttackType(attacktype),apply); _ApplyItemBonuses(proto,slot,apply); - if( slot==EQUIPMENT_SLOT_RANGED ) + if (slot==EQUIPMENT_SLOT_RANGED) _ApplyAmmoBonuses(); ApplyItemEquipSpell(item,apply); ApplyEnchantment(item, apply); - if(proto->Socket[0].Color) //only (un)equipping of items with sockets can influence metagems, so no need to waste time with normal items - CorrectMetaGemEnchants(slot, apply); - sLog.outDebug("_ApplyItemMods complete."); } @@ -7095,9 +7122,9 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl case ITEM_MOD_RANGED_ATTACK_POWER: HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply); break; - case ITEM_MOD_FERAL_ATTACK_POWER: - ApplyFeralAPBonus(int32(val), apply); - break; +// case ITEM_MOD_FERAL_ATTACK_POWER: +// ApplyFeralAPBonus(int32(val), apply); +// break; case ITEM_MOD_MANA_REGENERATION: ApplyManaRegenBonus(int32(val), apply); break; @@ -8686,40 +8713,39 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) break; case 3703: // Shattrath City case 4384: // SA - /*if (bg && bg->GetTypeID() == BATTLEGROUND_SA) - bg->FillInitialWorldStates(data); + if (bg && bg->GetTypeID() == BATTLEGROUND_SA) + bg->FillInitialWorldStates(data); else - {*/ + { // 1-3 A defend, 4-6 H defend, 7-9 unk defend, 1 - ok, 2 - half destroyed, 3 - destroyed - data << uint32(0xf09) << uint32(0x4); // 7 3849 Gate of Temple - data << uint32(0xe36) << uint32(0x4); // 8 3638 Gate of Yellow Moon - data << uint32(0xe27) << uint32(0x4); // 9 3623 Gate of Green Emerald - data << uint32(0xe24) << uint32(0x4); // 10 3620 Gate of Blue Sapphire - data << uint32(0xe21) << uint32(0x4); // 11 3617 Gate of Red Sun - data << uint32(0xe1e) << uint32(0x4); // 12 3614 Gate of Purple Ametyst + data << uint32(0xf09) << uint32(0x0); // 7 3849 Gate of Temple + data << uint32(0xe36) << uint32(0x0); // 8 3638 Gate of Yellow Moon + data << uint32(0xe27) << uint32(0x0); // 9 3623 Gate of Green Emerald + data << uint32(0xe24) << uint32(0x0); // 10 3620 Gate of Blue Sapphire + data << uint32(0xe21) << uint32(0x0); // 11 3617 Gate of Red Sun + data << uint32(0xe1e) << uint32(0x0); // 12 3614 Gate of Purple Ametyst data << uint32(0xdf3) << uint32(0x0); // 13 3571 bonus timer (1 - on, 0 - off) data << uint32(0xded) << uint32(0x0); // 14 3565 Horde Attacker - data << uint32(0xdec) << uint32(0x1); // 15 3564 Alliance Attacker + data << uint32(0xdec) << uint32(0x0); // 15 3564 Alliance Attacker // End Round (timer), better explain this by example, eg. ends in 19:59 -> A:BC - data << uint32(0xde9) << uint32(0x9); // 16 3561 C - data << uint32(0xde8) << uint32(0x5); // 17 3560 B - data << uint32(0xde7) << uint32(0x19); // 18 3559 A - data << uint32(0xe35) << uint32(0x1); // 19 3637 East g - Horde control - data << uint32(0xe34) << uint32(0x1); // 20 3636 West g - Horde control - data << uint32(0xe33) << uint32(0x1); // 21 3635 South g - Horde control + data << uint32(0xde9) << uint32(0x0); // 16 3561 C + data << uint32(0xde8) << uint32(0x0); // 17 3560 B + data << uint32(0xde7) << uint32(0x0); // 18 3559 A + data << uint32(0xe35) << uint32(0x0); // 19 3637 East g - Horde control + data << uint32(0xe34) << uint32(0x0); // 20 3636 West g - Horde control + data << uint32(0xe33) << uint32(0x0); // 21 3635 South g - Horde control data << uint32(0xe32) << uint32(0x0); // 22 3634 East g - Alliance control data << uint32(0xe31) << uint32(0x0); // 23 3633 West g - Alliance control data << uint32(0xe30) << uint32(0x0); // 24 3632 South g - Alliance control - data << uint32(0xe2f) << uint32(0x1); // 25 3631 Chamber of Ancients - Horde control + data << uint32(0xe2f) << uint32(0x0); // 25 3631 Chamber of Ancients - Horde control data << uint32(0xe2e) << uint32(0x0); // 26 3630 Chamber of Ancients - Alliance control data << uint32(0xe2d) << uint32(0x0); // 27 3629 Beach1 - Horde control data << uint32(0xe2c) << uint32(0x0); // 28 3628 Beach2 - Horde control - data << uint32(0xe2b) << uint32(0x1); // 29 3627 Beach1 - Alliance control - data << uint32(0xe2a) << uint32(0x1); // 30 3626 Beach2 - Alliance control + data << uint32(0xe2b) << uint32(0x0); // 29 3627 Beach1 - Alliance control + data << uint32(0xe2a) << uint32(0x0); // 30 3626 Beach2 - Alliance control // and many unks... - //} - break; + } break; case 4406: // Ring of Valor if (bg && bg->GetTypeID() == BATTLEGROUND_RV) @@ -9584,7 +9610,7 @@ uint8 Player::_CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, if (curcount + count > limitEntry->maxCount) { if (no_space_count) - *no_space_count = count + curcount - limitEntry->maxCount; + *no_space_count = count + curcount - limitEntry->maxCount; return EQUIP_ERR_CANT_CARRY_MORE_OF_THIS; // attempt add too many limit category items } } @@ -10692,6 +10718,12 @@ uint8 Player::CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *p if (!pItem) return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND; + if (pItem->m_lootGenerated) + { + GetSession()->DoLootRelease(GetLootGUID()); + return EQUIP_ERR_OK; + } + uint32 count = pItem->GetCount(); sLog.outDebug( "STORAGE: CanBankItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount()); @@ -10887,7 +10919,28 @@ uint8 Player::CanUseItem( Item *pItem, bool not_loading ) const if (pItem->GetSkill() != 0) { - if (GetSkillValue( pItem->GetSkill() ) == 0) + bool allowEquip = false; + uint32 itemSkill = pItem->GetSkill(); + // Armor that is binded to account can "morph" from plate to mail, etc. if skill is not learned yet. + if (pProto->Quality == ITEM_QUALITY_HEIRLOOM && pProto->Class == ITEM_CLASS_ARMOR && !HasSkill(itemSkill)) + { + // TODO: when you right-click already equipped item it throws EQUIP_ERR_NO_REQUIRED_PROFICIENCY. + + // In fact it's a visual bug, everything works properly... I need sniffs of operations with + // binded to account items from off server. + + switch (this->getClass()) + { + case CLASS_HUNTER: + case CLASS_SHAMAN: + allowEquip = (itemSkill == SKILL_MAIL); + break; + case CLASS_PALADIN: + allowEquip = (itemSkill == SKILL_PLATE_MAIL); + break; + } + } + if (!allowEquip && GetSkillValue(itemSkill) == 0) return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; } @@ -12131,7 +12184,7 @@ void Player::SwapItem( uint16 src, uint16 dst ) // bag swap (with items exchange) case if(emptyBag && fullBag) { - ItemPrototype const* emotyProto = emptyBag->GetProto(); + ItemPrototype const* emptyProto = emptyBag->GetProto(); uint32 count = 0; @@ -12142,7 +12195,7 @@ void Player::SwapItem( uint16 src, uint16 dst ) continue; ItemPrototype const* bagItemProto = bagItem->GetProto(); - if (!bagItemProto || !ItemCanGoIntoBag(bagItemProto, emotyProto)) + if (!bagItemProto || !ItemCanGoIntoBag(bagItemProto, emptyProto)) { // one from items not go to empty target bag SendEquipError( EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG, pSrcItem, pDstItem ); @@ -12196,6 +12249,46 @@ void Player::SwapItem( uint16 src, uint16 dst ) else if (IsEquipmentPos(src)) EquipItem(eDest2, pDstItem, true); + // if player is moving bags and is looting an item inside this bag + // release the loot + if (GetLootGUID()) + { + bool released = false; + if (IsBagPos(src)) + { + Bag* bag = (Bag*)pSrcItem; + for(int i=0; i < bag->GetBagSize(); ++i) + { + if (Item *bagItem = bag->GetItemByPos(i)) + { + if (bagItem->m_lootGenerated) + { + m_session->DoLootRelease(GetLootGUID()); + released = true; // so we don't need to look at dstBag + break; + } + } + } + } + + if (!released && IsBagPos(dst) && pDstItem) + { + Bag* bag = (Bag*)pDstItem; + for(int i=0; i < bag->GetBagSize(); ++i) + { + if (Item *bagItem = bag->GetItemByPos(i)) + { + if (bagItem->m_lootGenerated) + { + m_session->DoLootRelease(GetLootGUID()); + released = true; // not realy needed here + break; + } + } + } + } + } + AutoUnequipOffhandIfNeed(); } @@ -12792,8 +12885,8 @@ void Player::ApplyEnchantment(Item *item, EnchantmentSlot slot, bool apply, bool HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply); sLog.outDebug("+ %u RANGED_ATTACK_POWER", enchant_amount); break; - case ITEM_MOD_FERAL_ATTACK_POWER: - ((Player*)this)->ApplyFeralAPBonus(enchant_amount, apply); +// case ITEM_MOD_FERAL_ATTACK_POWER: +// ((Player*)this)->ApplyFeralAPBonus(enchant_amount, apply); sLog.outDebug("+ %u FERAL_ATTACK_POWER", enchant_amount); break; case ITEM_MOD_MANA_REGENERATION: @@ -15038,6 +15131,7 @@ void Player::SendQuestReward( Quest const *pQuest, uint32 XP, Object * questGive data << uint32(10*Trinity::Honor::hk_honor_at_level(getLevel(), pQuest->GetRewHonorableKills())); data << uint32(pQuest->GetBonusTalents()); // bonus talents + data << uint32(0); GetSession()->SendPacket( &data ); if (pQuest->GetQuestCompleteScript() != 0) @@ -15125,7 +15219,7 @@ void Player::SendQuestUpdateAddItem( Quest const* pQuest, uint32 item_idx, uint3 void Player::SendQuestUpdateAddCreatureOrGo( Quest const* pQuest, uint64 guid, uint32 creatureOrGO_idx, uint32 old_count, uint32 add_count ) { - assert(old_count + add_count < 256 && "mob/GO count store in 8 bits 2^8 = 256 (0..256)"); + assert(old_count + add_count < 65536 && "mob/GO count store in 16 bits 2^16 = 65536 (0..65536)"); int32 entry = pQuest->ReqCreatureOrGOId[ creatureOrGO_idx ]; if (entry < 0) @@ -15631,13 +15725,16 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) m_taxi.ClearTaxiDestinations(); } - if(uint32 node_id = m_taxi.GetTaxiSource()) + if (uint32 node_id = m_taxi.GetTaxiSource()) { // save source node as recall coord to prevent recall and fall from sky TaxiNodesEntry const* nodeEntry = sTaxiNodesStore.LookupEntry(node_id); - assert(nodeEntry); // checked in m_taxi.LoadTaxiDestinationsFromString - mapId = nodeEntry->map_id; - Relocate(nodeEntry->x, nodeEntry->y, nodeEntry->z,0.0f); + if (nodeEntry && nodeEntry->map_id == GetMapId()) + { + assert(nodeEntry); // checked in m_taxi.LoadTaxiDestinationsFromString + mapId = nodeEntry->map_id; + Relocate(nodeEntry->x, nodeEntry->y, nodeEntry->z,0.0f); + } // flight will started later } @@ -17209,7 +17306,7 @@ void Player::_SaveAuras() CharacterDatabase.PExecute("INSERT INTO character_aura (guid,caster_guid,spell,effect_mask,recalculate_mask,stackcount,amount0,amount1,amount2,base_amount0,base_amount1,base_amount2,maxduration,remaintime,remaincharges) " "VALUES ('%u', '" UI64FMTD "', '%u', '%u', '%u', '%u', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u')", - GetGUIDLow(), itr->second->GetCasterGUID(), itr->second->GetId(), effMask, recalculateMask, + GetGUIDLow(), itr->second->GetCasterGUID(), itr->second->GetId(), effMask, recalculateMask, itr->second->GetStackAmount(), damage[0], damage[1], damage[2], baseDamage[0], baseDamage[1], baseDamage[2], itr->second->GetMaxDuration(), itr->second->GetDuration(),itr->second->GetCharges()); } @@ -17980,7 +18077,7 @@ void Player::Whisper(const std::string& text, uint32 language,uint64 receiver) if (language != LANG_ADDON) { data.Initialize(SMSG_MESSAGECHAT, 200); - rPlayer->BuildPlayerChat(&data, CHAT_MSG_REPLY, text, language); + rPlayer->BuildPlayerChat(&data, CHAT_MSG_WHISPER_INFORM, text, language); GetSession()->SendPacket(&data); } } @@ -19197,6 +19294,7 @@ void Player::UpdateHomebindTime(uint32 time) if (time >= m_HomebindTimer) { // teleport to nearest graveyard + SetPhaseMask(1,true); RepopAtGraveyard(); } else @@ -19212,6 +19310,7 @@ void Player::UpdateHomebindTime(uint32 time) data << uint32(1); GetSession()->SendPacket(&data); sLog.outDebug("PLAYER: Player '%s' (GUID: %u) will be teleported to homebind in 60 seconds", GetName(),GetGUIDLow()); + SetPhaseMask(2,true); } } |