diff options
Diffstat (limited to 'src/game/Player.cpp')
-rw-r--r-- | src/game/Player.cpp | 307 |
1 files changed, 189 insertions, 118 deletions
diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 64234151fc7..7ad1be5a478 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -355,8 +355,11 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this) m_regenTimer = 0; m_weaponChangeTimer = 0; - m_breathTimer = 0; - m_isunderwater = UNDERWATER_NONE; + for (int i=0; i<MAX_TIMERS; i++) + m_MirrorTimer[i] = DISABLED_MIRROR_TIMER; + + m_MirrorTimerFlags = UNDERWATER_NONE; + m_MirrorTimerFlagsLast = UNDERWATER_NONE; m_isInWater = false; m_drunkTimer = 0; m_drunk = 0; @@ -856,25 +859,14 @@ bool Player::StoreNewItemInBestSlots(uint32 titem_id, uint32 titem_amount) return false; } -void Player::StartMirrorTimer(MirrorTimerType Type, uint32 MaxValue) -{ - uint32 BreathRegen = (uint32)-1; - - WorldPacket data(SMSG_START_MIRROR_TIMER, (21)); - data << (uint32)Type; - data << MaxValue; - data << MaxValue; - data << BreathRegen; - data << (uint8)0; - data << (uint32)0; // spell id - GetSession()->SendPacket(&data); -} - -void Player::ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, uint32 Regen) +void Player::SendMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, int32 Regen) { - if(Type==BREATH_TIMER) - m_breathTimer = ((MaxValue + 1*IN_MILISECONDS) - CurrentValue) / Regen; - + if (MaxValue == DISABLED_MIRROR_TIMER) + { + if (CurrentValue!=DISABLED_MIRROR_TIMER) + StopMirrorTimer(Type); + return; + } WorldPacket data(SMSG_START_MIRROR_TIMER, (21)); data << (uint32)Type; data << CurrentValue; @@ -887,9 +879,7 @@ void Player::ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 Cur void Player::StopMirrorTimer(MirrorTimerType Type) { - if(Type==BREATH_TIMER) - m_breathTimer = 0; - + m_MirrorTimer[Type] = DISABLED_MIRROR_TIMER; WorldPacket data(SMSG_STOP_MIRROR_TIMER, 4); data << (uint32)Type; GetSession()->SendPacket( &data ); @@ -900,12 +890,22 @@ void Player::EnvironmentalDamage(uint64 guid, EnviromentalDamage type, uint32 da if(!isAlive() || isGameMaster()) return; + // Absorb, resist some environmental damage type + uint32 absorb = 0; + uint32 resist = 0; + if (type == DAMAGE_LAVA) + CalcAbsorbResist(this, SPELL_SCHOOL_MASK_FIRE, DIRECT_DAMAGE, damage, &absorb, &resist); + else if (type == DAMAGE_SLIME) + CalcAbsorbResist(this, SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, damage, &absorb, &resist); + + damage-=absorb+resist; + WorldPacket data(SMSG_ENVIRONMENTALDAMAGELOG, (21)); data << (uint64)guid; data << (uint8)(type!=DAMAGE_FALL_TO_VOID ? type : DAMAGE_FALL); data << (uint32)damage; - data << (uint32)0; - data << (uint32)0; + data << (uint32)absorb; // absorb + data << (uint32)resist; // resist SendMessageToSet(&data, true); DealDamage(this, damage, NULL, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); @@ -925,96 +925,153 @@ void Player::EnvironmentalDamage(uint64 guid, EnviromentalDamage type, uint32 da } } -void Player::HandleDrowning() +int32 Player::getMaxTimer(MirrorTimerType timer) { - if(!(m_isunderwater&~UNDERWATER_INLAVA)) - return; - - //if player is GM, have waterbreath, is dead or if breathing is disabled then return - if(isGameMaster() || !isAlive() || HasAuraType(SPELL_AURA_WATER_BREATHING) || GetSession()->GetSecurity() >= sWorld.getConfig(CONFIG_DISABLE_BREATHING)) + switch (timer) { - StopMirrorTimer(BREATH_TIMER); - // drop every flag _except_ LAVA - otherwise waterbreathing will prevent lava damage - m_isunderwater &= UNDERWATER_INLAVA; - return; + case FATIGUE_TIMER: + return MINUTE*IN_MILISECONDS; + case BREATH_TIMER: + { + if (!isAlive() || HasAuraType(SPELL_AURA_WATER_BREATHING) || GetSession()->GetSecurity() >= sWorld.getConfig(CONFIG_DISABLE_BREATHING)) + return DISABLED_MIRROR_TIMER; + int32 UnderWaterTime = 3*MINUTE*IN_MILISECONDS; + AuraList const& mModWaterBreathing = GetAurasByType(SPELL_AURA_MOD_WATER_BREATHING); + for(AuraList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i) + UnderWaterTime = uint32(UnderWaterTime * (100.0f + (*i)->GetModifier()->m_amount) / 100.0f); + return UnderWaterTime; + } + case FIRE_TIMER: + { + if (!isAlive()) + return DISABLED_MIRROR_TIMER; + return 1*IN_MILISECONDS; + } + default: + return 0; } + return 0; +} - uint32 UnderWaterTime = 3*MINUTE*IN_MILISECONDS; // default duration +void Player::UpdateMirrorTimers() +{ + // Desync flags for update on next HandleDrowning + if (m_MirrorTimerFlags) + m_MirrorTimerFlagsLast = ~m_MirrorTimerFlags; +} - AuraList const& mModWaterBreathing = GetAurasByType(SPELL_AURA_MOD_WATER_BREATHING); - for(AuraList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i) - UnderWaterTime = uint32(UnderWaterTime * (100.0f + (*i)->GetModifier()->m_amount) / 100.0f); +void Player::HandleDrowning(uint32 time_diff) +{ + if (!m_MirrorTimerFlags) + return; - if ((m_isunderwater & UNDERWATER_INWATER) && !(m_isunderwater & UNDERWATER_INLAVA) && isAlive()) + // In water + if (m_MirrorTimerFlags & UNDERWATER_INWATER) { - //single trigger timer - if (!(m_isunderwater & UNDERWATER_WATER_TRIGGER)) - { - m_isunderwater|= UNDERWATER_WATER_TRIGGER; - m_breathTimer = UnderWaterTime + 1*IN_MILISECONDS; - } - //single trigger "show Breathbar" - if ( m_breathTimer <= UnderWaterTime && !(m_isunderwater & UNDERWATER_WATER_BREATHB)) + // Breath timer not activated - activate it + if (m_MirrorTimer[BREATH_TIMER] == DISABLED_MIRROR_TIMER) { - m_isunderwater|= UNDERWATER_WATER_BREATHB; - StartMirrorTimer(BREATH_TIMER, UnderWaterTime); + m_MirrorTimer[BREATH_TIMER] = getMaxTimer(BREATH_TIMER); + SendMirrorTimer(BREATH_TIMER, m_MirrorTimer[BREATH_TIMER], m_MirrorTimer[BREATH_TIMER], -1); } - //continuous trigger drowning "Damage" - if ((m_breathTimer == 0) && (m_isunderwater & UNDERWATER_INWATER)) + else // If activated - do tick { - //TODO: Check this formula - uint64 guid = GetGUID(); - uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1); - - EnvironmentalDamage(guid, DAMAGE_DROWNING,damage); - m_breathTimer = 2000; + m_MirrorTimer[BREATH_TIMER]-=time_diff; + // Timer limit - need deal damage + if (m_MirrorTimer[BREATH_TIMER] < 0) + { + m_MirrorTimer[BREATH_TIMER]+= 1*IN_MILISECONDS; + // Calculate and deal damage + // TODO: Check this formula + uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1); + EnvironmentalDamage(GetGUID(), DAMAGE_DROWNING, damage); + } + else if (!(m_MirrorTimerFlagsLast & UNDERWATER_INWATER)) // Update time in client if need + SendMirrorTimer(BREATH_TIMER, getMaxTimer(BREATH_TIMER), m_MirrorTimer[BREATH_TIMER], -1); } } - //single trigger retract bar - else if (!(m_isunderwater & UNDERWATER_INWATER) && (m_isunderwater & UNDERWATER_WATER_TRIGGER) && (m_breathTimer > 0) && isAlive()) - { - uint32 BreathRegen = 10; - // m_breathTimer will be reduced in ModifyMirrorTimer - ModifyMirrorTimer(BREATH_TIMER, UnderWaterTime, m_breathTimer,BreathRegen); - m_isunderwater = UNDERWATER_WATER_BREATHB_RETRACTING; - } - //remove bar - else if ((m_breathTimer < 50) && !(m_isunderwater & UNDERWATER_INWATER) && (m_isunderwater == UNDERWATER_WATER_BREATHB_RETRACTING)) + else if (m_MirrorTimer[BREATH_TIMER] != DISABLED_MIRROR_TIMER) // Regen timer { - StopMirrorTimer(BREATH_TIMER); - m_isunderwater = UNDERWATER_NONE; + int32 UnderWaterTime = getMaxTimer(BREATH_TIMER); + // Need breath regen + m_MirrorTimer[BREATH_TIMER]+=10*time_diff; + if (m_MirrorTimer[BREATH_TIMER] >= UnderWaterTime || !isAlive()) + StopMirrorTimer(BREATH_TIMER); + else if (m_MirrorTimerFlagsLast & UNDERWATER_INWATER) + SendMirrorTimer(BREATH_TIMER, UnderWaterTime, m_MirrorTimer[BREATH_TIMER], 10); } -} -void Player::HandleLava() -{ - if ((m_isunderwater & UNDERWATER_INLAVA) && isAlive()) + // In dark water + if (m_MirrorTimerFlags & UNDERWARER_INDARKWATER) { - /* - * arrai: how is this supposed to work? UNDERWATER_INLAVA is always set in this scope! - // Single trigger Set BreathTimer - if (!(m_isunderwater & UNDERWATER_INLAVA)) + // Fatigue timer not activated - activate it + if (m_MirrorTimer[FATIGUE_TIMER] == DISABLED_MIRROR_TIMER) { - m_isunderwater|= UNDERWATER_WATER_BREATHB; - m_breathTimer = 1*IN_MILISECONDS; + m_MirrorTimer[FATIGUE_TIMER] = getMaxTimer(FATIGUE_TIMER); + SendMirrorTimer(FATIGUE_TIMER, m_MirrorTimer[FATIGUE_TIMER], m_MirrorTimer[FATIGUE_TIMER], -1); } - */ - // Reset BreathTimer and still in the lava - if (!m_breathTimer) + else { - uint64 guid = GetGUID(); - uint32 damage = urand(600, 700); // TODO: Get more detailed information about lava damage - - EnvironmentalDamage(guid, DAMAGE_LAVA, damage); - - m_breathTimer = 1*IN_MILISECONDS; + m_MirrorTimer[FATIGUE_TIMER]-=time_diff; + // Timer limit - need deal damage or teleport ghost to graveyard + if (m_MirrorTimer[FATIGUE_TIMER] < 0) + { + m_MirrorTimer[FATIGUE_TIMER]+= 1*IN_MILISECONDS; + if (isAlive()) // Calculate and deal damage + { + uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1); + EnvironmentalDamage(GetGUID(), DAMAGE_EXHAUSTED, damage); + } + else if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) // Teleport ghost to graveyard + RepopAtGraveyard(); + } + else if (!(m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER)) + SendMirrorTimer(FATIGUE_TIMER, getMaxTimer(FATIGUE_TIMER), m_MirrorTimer[FATIGUE_TIMER], -1); } } - else if (!isAlive()) // Disable breath timer and reset underwater flags + else if (m_MirrorTimer[FATIGUE_TIMER] != DISABLED_MIRROR_TIMER) // Regen timer + { + int32 DarkWaterTime = getMaxTimer(FATIGUE_TIMER); + m_MirrorTimer[FATIGUE_TIMER]+=10*time_diff; + if (m_MirrorTimer[FATIGUE_TIMER] >= DarkWaterTime || !isAlive()) + StopMirrorTimer(FATIGUE_TIMER); + else if (m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER) + SendMirrorTimer(FATIGUE_TIMER, DarkWaterTime, m_MirrorTimer[FATIGUE_TIMER], 10); + } + + if (m_MirrorTimerFlags & (UNDERWATER_INLAVA|UNDERWATER_INSLIME)) { - m_breathTimer = 0; - m_isunderwater = UNDERWATER_NONE; + // Breath timer not activated - activate it + if (m_MirrorTimer[FIRE_TIMER] == DISABLED_MIRROR_TIMER) + m_MirrorTimer[FIRE_TIMER] = getMaxTimer(FIRE_TIMER); + else + { + m_MirrorTimer[FIRE_TIMER]-=time_diff; + if (m_MirrorTimer[FIRE_TIMER] < 0) + { + m_MirrorTimer[FIRE_TIMER]+= 1*IN_MILISECONDS; + // Calculate and deal damage + // TODO: Check this formula + uint32 damage = urand(600, 700); + if (m_MirrorTimerFlags&UNDERWATER_INLAVA) + EnvironmentalDamage(GetGUID(), DAMAGE_LAVA, damage); + else + EnvironmentalDamage(GetGUID(), DAMAGE_SLIME, damage); + } + } } + else + m_MirrorTimer[FIRE_TIMER] = DISABLED_MIRROR_TIMER; + + // Recheck timers flag + m_MirrorTimerFlags&=~UNDERWATER_EXIST_TIMERS; + for (int i = 0; i< MAX_TIMERS; ++i) + if (m_MirrorTimer[i]!=DISABLED_MIRROR_TIMER) + { + m_MirrorTimerFlags|=UNDERWATER_EXIST_TIMERS; + break; + } + m_MirrorTimerFlagsLast = m_MirrorTimerFlags; } ///The player sobers by 256 every 10 seconds @@ -1279,21 +1336,8 @@ void Player::Update( uint32 p_time ) } } - //Breathtimer - if(m_breathTimer > 0) - { - if(p_time >= m_breathTimer) - m_breathTimer = 0; - else - m_breathTimer -= p_time; - - } - //Handle Water/drowning - HandleDrowning(); - - //Handle lava - HandleLava(); + HandleDrowning(p_time); //Handle detect stealth players if (m_DetectInvTimer > 0) @@ -19983,21 +20027,48 @@ PartyResult Player::CanUninviteFromGroup() const void Player::UpdateUnderwaterState( Map* m, float x, float y, float z ) { - float water_z = m->GetWaterLevel(x,y); - float terrain_z = m->GetHeight(x,y,z, false); // use .map base surface height - uint8 flag1 = m->GetTerrainType(x,y); + LiquidData liquid_status; + ZLiquidStatus res = m->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquid_status); + if (!res) + { + m_MirrorTimerFlags &= ~(UNDERWATER_INWATER|UNDERWATER_INLAVA|UNDERWATER_INSLIME|UNDERWARER_INDARKWATER); + // Small hack for enable breath in WMO + if (IsInWater()) + m_MirrorTimerFlags|=UNDERWATER_INWATER; + return; + } - //!Underwater check, not in water if underground or above water level - take UC royal quater for example - if (terrain_z <= INVALID_HEIGHT || z < (terrain_z-2) || z > (water_z - 2) ) - m_isunderwater &= ~UNDERWATER_INWATER; - else if ((z < (water_z - 2)) && (flag1 & 0x01)) - m_isunderwater |= UNDERWATER_INWATER; + // All liquids type - check under water position + if (liquid_status.type&(MAP_LIQUID_TYPE_WATER|MAP_LIQUID_TYPE_OCEAN|MAP_LIQUID_TYPE_MAGMA|MAP_LIQUID_TYPE_SLIME)) + { + if ( res & LIQUID_MAP_UNDER_WATER) + m_MirrorTimerFlags |= UNDERWATER_INWATER; + else + m_MirrorTimerFlags &= ~UNDERWATER_INWATER; + } - //!in lava check, anywhere under lava level - if ((terrain_z <= INVALID_HEIGHT || z < (terrain_z - 0)) && (flag1 == 0x00) && IsInWater()) - m_isunderwater |= UNDERWATER_INLAVA; + // Allow travel in dark water on taxi or transport + if (liquid_status.type & MAP_LIQUID_TYPE_DARK_WATER && !isInFlight() && !(GetUnitMovementFlags()&MOVEMENTFLAG_ONTRANSPORT)) + m_MirrorTimerFlags |= UNDERWARER_INDARKWATER; else - m_isunderwater &= ~UNDERWATER_INLAVA; + m_MirrorTimerFlags &= ~UNDERWARER_INDARKWATER; + + // in lava check, anywhere in lava level + if (liquid_status.type&MAP_LIQUID_TYPE_MAGMA) + { + if (res & (LIQUID_MAP_UNDER_WATER|LIQUID_MAP_IN_WATER|LIQUID_MAP_WATER_WALK)) + m_MirrorTimerFlags |= UNDERWATER_INLAVA; + else + m_MirrorTimerFlags &= ~UNDERWATER_INLAVA; + } + // in slime check, anywhere in slime level + if (liquid_status.type&MAP_LIQUID_TYPE_SLIME) + { + if (res & (LIQUID_MAP_UNDER_WATER|LIQUID_MAP_IN_WATER|LIQUID_MAP_WATER_WALK)) + m_MirrorTimerFlags |= UNDERWATER_INSLIME; + else + m_MirrorTimerFlags &= ~UNDERWATER_INSLIME; + } } void Player::SetCanParry( bool value ) |