diff --git a/src/game/DBCEnums.h b/src/game/DBCEnums.h index cc9014575..fc42bb5ec 100644 --- a/src/game/DBCEnums.h +++ b/src/game/DBCEnums.h @@ -221,7 +221,7 @@ enum AreaFlags AREA_FLAG_SLAVE_CAPITAL = 0x00000008, // city and city subsones AREA_FLAG_UNK3 = 0x00000010, // can't find common meaning AREA_FLAG_SLAVE_CAPITAL2 = 0x00000020, // slave capital city flag? - AREA_FLAG_UNK4 = 0x00000040, // many zones have this flag + AREA_FLAG_DUEL = 0x00000040, // zones where duels allowed AREA_FLAG_ARENA = 0x00000080, // arena, both instanced and world arenas AREA_FLAG_CAPITAL = 0x00000100, // main capital city flag AREA_FLAG_CITY = 0x00000200, // only for one zone named "City" (where it located?) diff --git a/src/game/Player.cpp b/src/game/Player.cpp index c0cf8a012..b954db9dc 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -1324,9 +1324,8 @@ void Player::Update( uint32 update_diff, uint32 p_time ) } } - Unit *owner = pVictim->GetOwner(); - Unit *u = owner ? owner : pVictim; - if (u->IsPvP() && (!duel || duel->opponent != u)) + Player *vOwner = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself(); + if (vOwner && vOwner->IsPvP() && !IsInDuelWith(vOwner)) { UpdatePvP(true); RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); @@ -6792,6 +6791,9 @@ void Player::UpdateArea(uint32 newArea) if (area) { + // check leave duel allowed area + CheckDuelArea(area); + // Dalaran restricted flight zone if ((area->flags & AREA_FLAG_CANNOT_FLY) && IsFreeFlying() && !isGameMaster() && !HasAura(58600)) CastSpell(this, 58600, true); // Restricted Flight Area @@ -6898,6 +6900,15 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) UpdateZoneDependentPets(); } +void Player::CheckDuelArea(AreaTableEntry const* areaEntry) +{ + if (!duel) + return; + + if (!(areaEntry->flags & AREA_FLAG_DUEL)) + DuelComplete(DUEL_FLED); +} + //If players are too far way of duel flag... then player loose the duel void Player::CheckDuelDistance(time_t currTime) { @@ -6905,8 +6916,12 @@ void Player::CheckDuelDistance(time_t currTime) return; GameObject* obj = GetMap()->GetGameObject(GetGuidValue(PLAYER_DUEL_ARBITER)); - if(!obj) + if (!obj) + { + // player not at duel start map + DuelComplete(DUEL_FLED); return; + } if (duel->outOfBound == 0) { @@ -6937,7 +6952,7 @@ void Player::CheckDuelDistance(time_t currTime) void Player::DuelComplete(DuelCompleteType type) { // duel not requested - if(!duel) + if (!duel) return; WorldPacket data(SMSG_DUEL_COMPLETE, (1)); @@ -6945,7 +6960,7 @@ void Player::DuelComplete(DuelCompleteType type) GetSession()->SendPacket(&data); duel->opponent->GetSession()->SendPacket(&data); - if(type != DUEL_INTERUPTED) + if (type != DUEL_INTERUPTED) { data.Initialize(SMSG_DUEL_WINNER, (1+20)); // we guess size data << (uint8)((type==DUEL_WON) ? 0 : 1); // 0 = just won; 1 = fled diff --git a/src/game/Player.h b/src/game/Player.h index ab487f7f0..98f2edb0d 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1717,7 +1717,9 @@ class MANGOS_DLL_SPEC Player : public Unit /** todo: -maybe move UpdateDuelFlag+DuelComplete to independent DuelHandler.. **/ DuelInfo *duel; + bool IsInDuelWith(Player const* player) const { return duel && duel->opponent == player && duel->startTime != 0; } void UpdateDuelFlag(time_t currTime); + void CheckDuelArea(AreaTableEntry const* areaEntry); void CheckDuelDistance(time_t currTime); void DuelComplete(DuelCompleteType type); void SendDuelCountdown(uint32 counter); diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 9c2f391ab..c4a547a35 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -640,14 +640,13 @@ void Spell::FillTargetMap() break; } - if(m_caster->GetTypeId() == TYPEID_PLAYER) + if (m_caster->GetTypeId() == TYPEID_PLAYER) { Player *me = (Player*)m_caster; for (UnitList::const_iterator itr = tmpUnitMap.begin(); itr != tmpUnitMap.end(); ++itr) { - Unit *owner = (*itr)->GetOwner(); - Unit *u = owner ? owner : (*itr); - if(u!=m_caster && u->IsPvP() && (!me->duel || me->duel->opponent != u)) + Player *targetOwner = (*itr)->GetCharmerOrOwnerPlayerOrPlayerItself(); + if (targetOwner && targetOwner != me && targetOwner->IsPvP() && !me->IsInDuelWith(targetOwner)) { me->UpdatePvP(true); me->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index b4aaa5509..8471096fd 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -7778,27 +7778,19 @@ void Spell::EffectDuel(SpellEffectIndex eff_idx) Player *target = (Player*)unitTarget; // caster or target already have requested duel - if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetObjectGuid()) ) + if (caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetObjectGuid())) return; // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities) - // Don't have to check the target's map since you cannot challenge someone across maps - uint32 mapid = caster->GetMapId(); - if( mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609) + AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetAreaId()); + if (casterAreaEntry && !(casterAreaEntry->flags & AREA_FLAG_DUEL)) { SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here return; } - AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId()); - if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) ) - { - SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here - return; - } - - AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId()); - if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) ) + AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetAreaId()); + if (targetAreaEntry && !(targetAreaEntry->flags & AREA_FLAG_DUEL)) { SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here return; diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index ab8d950e4..28c2f2d87 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -607,7 +607,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa // duel ends when player has 1 or less hp bool duel_hasEnded = false; - if(pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health-1)) + if (pVictim->GetTypeId() == TYPEID_PLAYER && ((Player*)pVictim)->duel && damage >= (health-1)) { // prevent kill only if killed in duel and killed by opponent or opponent controlled creature if(((Player*)pVictim)->duel->opponent==this || ((Player*)pVictim)->duel->opponent->GetObjectGuid() == GetOwnerGuid()) @@ -5361,15 +5361,15 @@ FactionTemplateEntry const* Unit::getFactionTemplateEntry() const bool Unit::IsHostileTo(Unit const* unit) const { // always non-hostile to self - if(unit==this) + if (unit == this) return false; // always non-hostile to GM in GM mode - if(unit->GetTypeId()==TYPEID_PLAYER && ((Player const*)unit)->isGameMaster()) + if (unit->GetTypeId() == TYPEID_PLAYER && ((Player const*)unit)->isGameMaster()) return false; // always hostile to enemy - if(getVictim()==unit || unit->getVictim()==this) + if (getVictim() == unit || unit->getVictim() == this) return true; // test pet/charm masters instead pers/charmeds @@ -5377,49 +5377,49 @@ bool Unit::IsHostileTo(Unit const* unit) const Unit const* targetOwner = unit->GetCharmerOrOwner(); // always hostile to owner's enemy - if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner)) + if (testerOwner && (testerOwner->getVictim() == unit || unit->getVictim() == testerOwner)) return true; // always hostile to enemy owner - if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this)) + if (targetOwner && (getVictim() == targetOwner || targetOwner->getVictim() == this)) return true; // always hostile to owner of owner's enemy - if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner)) + if (testerOwner && targetOwner && (testerOwner->getVictim() == targetOwner || targetOwner->getVictim() == testerOwner)) return true; Unit const* tester = testerOwner ? testerOwner : this; Unit const* target = targetOwner ? targetOwner : unit; // always non-hostile to target with common owner, or to owner/pet - if(tester==target) + if (tester == target) return false; // special cases (Duel, etc) - if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER) + if (tester->GetTypeId() == TYPEID_PLAYER && target->GetTypeId() == TYPEID_PLAYER) { Player const* pTester = (Player const*)tester; Player const* pTarget = (Player const*)target; // Duel - if(pTester->duel && pTester->duel->opponent == pTarget && pTester->duel->startTime != 0) + if (pTester->IsInDuelWith(pTarget)) return true; // Group - if(pTester->GetGroup() && pTester->GetGroup()==pTarget->GetGroup()) + if (pTester->GetGroup() && pTester->GetGroup() == pTarget->GetGroup()) return false; // Sanctuary - if(pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY)) + if (pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY)) return false; // PvP FFA state - if(pTester->IsFFAPvP() && pTarget->IsFFAPvP()) + if (pTester->IsFFAPvP() && pTarget->IsFFAPvP()) return true; //= PvP states // Green/Blue (can't attack) - if(pTester->GetTeam()==pTarget->GetTeam()) + if (pTester->GetTeam() == pTarget->GetTeam()) return false; // Red (can attack) if true, Blue/Yellow (can't attack) in another case @@ -5473,15 +5473,15 @@ bool Unit::IsHostileTo(Unit const* unit) const bool Unit::IsFriendlyTo(Unit const* unit) const { // always friendly to self - if(unit==this) + if (unit == this) return true; // always friendly to GM in GM mode - if(unit->GetTypeId()==TYPEID_PLAYER && ((Player const*)unit)->isGameMaster()) + if (unit->GetTypeId() == TYPEID_PLAYER && ((Player const*)unit)->isGameMaster()) return true; // always non-friendly to enemy - if(getVictim()==unit || unit->getVictim()==this) + if (getVictim() == unit || unit->getVictim() == this) return false; // test pet/charm masters instead pers/charmeds @@ -5489,49 +5489,49 @@ bool Unit::IsFriendlyTo(Unit const* unit) const Unit const* targetOwner = unit->GetCharmerOrOwner(); // always non-friendly to owner's enemy - if(testerOwner && (testerOwner->getVictim()==unit || unit->getVictim()==testerOwner)) + if (testerOwner && (testerOwner->getVictim() == unit || unit->getVictim() == testerOwner)) return false; // always non-friendly to enemy owner - if(targetOwner && (getVictim()==targetOwner || targetOwner->getVictim()==this)) + if (targetOwner && (getVictim() == targetOwner || targetOwner->getVictim() == this)) return false; // always non-friendly to owner of owner's enemy - if(testerOwner && targetOwner && (testerOwner->getVictim()==targetOwner || targetOwner->getVictim()==testerOwner)) + if (testerOwner && targetOwner && (testerOwner->getVictim() == targetOwner || targetOwner->getVictim() == testerOwner)) return false; Unit const* tester = testerOwner ? testerOwner : this; Unit const* target = targetOwner ? targetOwner : unit; // always friendly to target with common owner, or to owner/pet - if(tester==target) + if (tester == target) return true; // special cases (Duel) - if(tester->GetTypeId()==TYPEID_PLAYER && target->GetTypeId()==TYPEID_PLAYER) + if (tester->GetTypeId() == TYPEID_PLAYER && target->GetTypeId() == TYPEID_PLAYER) { Player const* pTester = (Player const*)tester; Player const* pTarget = (Player const*)target; // Duel - if(pTester->duel && pTester->duel->opponent == target && pTester->duel->startTime != 0) + if (pTester->IsInDuelWith(pTarget)) return false; // Group - if(pTester->GetGroup() && pTester->GetGroup()==pTarget->GetGroup()) + if (pTester->GetGroup() && pTester->GetGroup() == pTarget->GetGroup()) return true; // Sanctuary - if(pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY)) + if (pTarget->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY) && pTester->HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY)) return true; // PvP FFA state - if(pTester->IsFFAPvP() && pTarget->IsFFAPvP()) + if (pTester->IsFFAPvP() && pTarget->IsFFAPvP()) return false; //= PvP states // Green/Blue (non-attackable) - if(pTester->GetTeam()==pTarget->GetTeam()) + if (pTester->GetTeam() == pTarget->GetTeam()) return true; // Blue (friendly/non-attackable) if not PVP, or Yellow/Red in another case (attackable) @@ -5883,6 +5883,15 @@ Player* Unit::GetCharmerOrOwnerPlayerOrPlayerItself() return GetTypeId()==TYPEID_PLAYER ? (Player*)this : NULL; } +Player const* Unit::GetCharmerOrOwnerPlayerOrPlayerItself() const +{ + ObjectGuid guid = GetCharmerOrOwnerGuid(); + if (guid.IsPlayer()) + return ObjectAccessor::FindPlayer(guid); + + return GetTypeId() == TYPEID_PLAYER ? (Player const*)this : NULL; +} + Pet* Unit::GetPet() const { if (ObjectGuid pet_guid = GetPetGuid()) @@ -7700,18 +7709,20 @@ void Unit::SetInCombatWith(Unit* enemy) Unit* eOwner = enemy->GetCharmerOrOwnerOrSelf(); if (eOwner->IsPvP()) { - SetInCombatState(true,enemy); + SetInCombatState(true, enemy); return; } //check for duel if (eOwner->GetTypeId() == TYPEID_PLAYER && ((Player*)eOwner)->duel) { - Unit const* myOwner = GetCharmerOrOwnerOrSelf(); - if(((Player const*)eOwner)->duel->opponent == myOwner) + if (Player const* myOwner = GetCharmerOrOwnerPlayerOrPlayerItself()) { - SetInCombatState(true,enemy); - return; + if (myOwner->IsInDuelWith((Player const*)eOwner)) + { + SetInCombatState(true,enemy); + return; + } } } @@ -10376,7 +10387,7 @@ void Unit::SetContestedPvP(Player *attackedPlayer) { Player* player = GetCharmerOrOwnerPlayerOrPlayerItself(); - if (!player || (attackedPlayer && (attackedPlayer == player || (player->duel && player->duel->opponent == attackedPlayer)))) + if (!player || (attackedPlayer && (attackedPlayer == player || player->IsInDuelWith(attackedPlayer)))) return; player->SetContestedPvPTimer(30000); @@ -10792,16 +10803,22 @@ bool Unit::IsAllowedDamageInArea(Unit* pVictim) const if (pVictim == this) return true; - // non player controlled unit can damage anywhere - if (!IsCharmerOrOwnerPlayerOrPlayerItself()) - return true; - // can damage own pet anywhere if (pVictim->GetOwnerGuid() == GetObjectGuid()) return true; + // non player controlled unit can damage anywhere + Player const* pOwner = GetCharmerOrOwnerPlayerOrPlayerItself(); + if (!pOwner) + return true; + // can damage non player controlled victim anywhere - if (!pVictim->IsCharmerOrOwnerPlayerOrPlayerItself()) + Player const* vOwner = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself(); + if (!vOwner) + return true; + + // can damage opponent in duel + if (pOwner->IsInDuelWith(vOwner)) return true; // can't damage player controlled unit by player controlled unit in sanctuary diff --git a/src/game/Unit.h b/src/game/Unit.h index 9bef00816..aa92cf717 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1530,6 +1530,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject } bool IsCharmerOrOwnerPlayerOrPlayerItself() const; Player* GetCharmerOrOwnerPlayerOrPlayerItself(); + Player const* GetCharmerOrOwnerPlayerOrPlayerItself() const; float GetCombatDistance( const Unit* target ) const; void SetPet(Pet* pet); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index fc60b0ac3..7fa75d44f 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "11556" + #define REVISION_NR "11557" #endif // __REVISION_NR_H__