18508 | | bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const |
18509 | | { |
18510 | | for(ItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end();++itr) |
18511 | | if(itr->pos == this->pos) |
18512 | | return true; |
18513 | | |
18514 | | return false; |
| 18515 | void Player::HandleFallDamage(MovementInfo& movementInfo) |
| 18516 | { |
| 18517 | //Players with Feather Fall or low fall time, or physical immunity (charges used) are ignored |
| 18518 | if (!isInFlight() && movementInfo.fallTime > 1100 && !isDead() && !isGameMaster() && |
| 18519 | !HasAuraType(SPELL_AURA_HOVER) && !HasAuraType(SPELL_AURA_FEATHER_FALL) && |
| 18520 | !HasAuraType(SPELL_AURA_FLY) && !IsImmunedToDamage(SPELL_SCHOOL_MASK_NORMAL,true) ) |
| 18521 | { |
| 18522 | //Safe fall, fall time reduction |
| 18523 | int32 safe_fall = GetTotalAuraModifier(SPELL_AURA_SAFE_FALL); |
| 18524 | uint32 fall_time = (movementInfo.fallTime > (safe_fall*10)) ? movementInfo.fallTime - (safe_fall*10) : 0; |
| 18525 | |
| 18526 | if(fall_time > 1100) //Prevent damage if fall time < 1100 |
| 18527 | { |
| 18528 | //Fall Damage calculation |
| 18529 | float fallperc = float(fall_time)/1100; |
| 18530 | uint32 damage = (uint32)(((fallperc*fallperc -1) / 9 * GetMaxHealth())*sWorld.getRate(RATE_DAMAGE_FALL)); |
| 18531 | |
| 18532 | float height = movementInfo.z; |
| 18533 | UpdateGroundPositionZ(movementInfo.x,movementInfo.y,height); |
| 18534 | |
| 18535 | if (damage > 0) |
| 18536 | { |
| 18537 | //Prevent fall damage from being more than the player maximum health |
| 18538 | if (damage > GetMaxHealth()) |
| 18539 | damage = GetMaxHealth(); |
| 18540 | |
| 18541 | // Gust of Wind |
| 18542 | if (GetDummyAura(43621)) |
| 18543 | damage = GetMaxHealth()/2; |
| 18544 | |
| 18545 | EnvironmentalDamage(GetGUID(), DAMAGE_FALL, damage); |
| 18546 | } |
| 18547 | |
| 18548 | //Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction |
| 18549 | DEBUG_LOG("FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d" , movementInfo.z, height, GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall); |
| 18550 | } |
| 18551 | } |
| 18552 | } |
| 18553 | |
| 18554 | void Player::HandleFallUnderMap() |
| 18555 | { |
| 18556 | if(InBattleGround() && GetBattleGround() |
| 18557 | && GetBattleGround()->HandlePlayerUnderMap(this)) |
| 18558 | { |
| 18559 | // do nothing, the handle already did if returned true |
| 18560 | } |
| 18561 | else |
| 18562 | { |
| 18563 | // NOTE: this is actually called many times while falling |
| 18564 | // even after the player has been teleported away |
| 18565 | // TODO: discard movement packets after the player is rooted |
| 18566 | if(isAlive()) |
| 18567 | { |
| 18568 | EnvironmentalDamage(GetGUID(),DAMAGE_FALL_TO_VOID, GetMaxHealth()); |
| 18569 | // change the death state to CORPSE to prevent the death timer from |
| 18570 | // starting in the next player update |
| 18571 | KillPlayer(); |
| 18572 | BuildPlayerRepop(); |
| 18573 | } |
| 18574 | |
| 18575 | // cancel the death timer here if started |
| 18576 | RepopAtGraveyard(); |
| 18577 | } |
| 18578 | } |
| 18579 | |
| 18580 | void Player::Possess(Unit *target) |
| 18581 | { |
| 18582 | if(!target || target == this) |
| 18583 | return; |
| 18584 | |
| 18585 | // Don't allow possession of someone else's pet |
| 18586 | if(target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isPet() && target != GetPet()) |
| 18587 | return; |
| 18588 | |
| 18589 | // Don't allow possession on transports or when in flight; also remove possession from the now-to-be-possessed |
| 18590 | if (target->GetTypeId() == TYPEID_PLAYER) |
| 18591 | { |
| 18592 | if (((Player*)target)->m_transport || ((Player*)target)->isInFlight()) |
| 18593 | return; |
| 18594 | if (target->isPossessing()) |
| 18595 | ((Player*)target)->RemovePossess(true); |
| 18596 | } |
| 18597 | |
| 18598 | // Remove any previous possession from the target |
| 18599 | if (target->isPossessedByPlayer()) |
| 18600 | ((Player*)target->GetCharmer())->RemovePossess(false); |
| 18601 | else if (target->isCharmed()) |
| 18602 | target->UncharmSelf(); // Target isn't possessed, but charmed; uncharm before possessing |
| 18603 | |
| 18604 | // Remove our previous possession |
| 18605 | if (isPossessing()) |
| 18606 | RemovePossess(true); |
| 18607 | else if (GetCharm()) // We are charming a creature, not possessing it; uncharm ourself first |
| 18608 | Uncharm(); |
| 18609 | |
| 18610 | // Interrupt any current casting of the target |
| 18611 | if(target->IsNonMeleeSpellCasted(true)) |
| 18612 | target->InterruptNonMeleeSpells(true); |
| 18613 | |
| 18614 | // Update the proper unit fields |
| 18615 | SetPossessedTarget(target); |
| 18616 | |
| 18617 | target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction()); |
| 18618 | target->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); |
| 18619 | target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5); |
| 18620 | target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); |
| 18621 | SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); |
| 18622 | SetUInt64Value(PLAYER_FARSIGHT, target->GetGUID()); |
| 18623 | |
| 18624 | if(target->GetTypeId() == TYPEID_UNIT) |
| 18625 | { |
| 18626 | // Set target to active in the grid and place it in the world container to be picked up by all regular player cell visits |
| 18627 | Map* map = target->GetMap(); |
| 18628 | map->SwitchGridContainers((Creature*)target, true); |
| 18629 | target->setActive(true); |
| 18630 | |
| 18631 | ((Creature*)target)->InitPossessedAI(); // Initialize the possessed AI |
| 18632 | target->StopMoving(); |
| 18633 | target->GetMotionMaster()->Clear(false); |
| 18634 | target->GetMotionMaster()->MoveIdle(); |
| 18635 | } |
| 18636 | |
| 18637 | target->CombatStop(); |
| 18638 | target->DeleteThreatList(); |
| 18639 | |
| 18640 | // Pets already have a properly initialized CharmInfo, don't overwrite it. |
| 18641 | if(target->GetTypeId() == TYPEID_PLAYER || (target->GetTypeId() == TYPEID_UNIT && !((Creature*)target)->isPet())) |
| 18642 | { |
| 18643 | CharmInfo* charmInfo = target->InitCharmInfo(target); |
| 18644 | charmInfo->InitPossessCreateSpells(); |
| 18645 | } |
| 18646 | |
| 18647 | // Disable control for target player and remove AFK |
| 18648 | if(target->GetTypeId() == TYPEID_PLAYER) |
| 18649 | { |
| 18650 | if(((Player*)target)->isAFK()) |
| 18651 | ((Player*)target)->ToggleAFK(); |
| 18652 | ((Player*)target)->SetViewport(target->GetGUID(), false); |
| 18653 | } |
| 18654 | |
| 18655 | // Set current viewport to target unit, controllable |
| 18656 | SetViewport(target->GetGUID(), true); |
| 18657 | |
| 18658 | PossessSpellInitialize(); |
| 18659 | } |
| 18660 | |
| 18661 | void Player::RemovePossess(bool attack) |
| 18662 | { |
| 18663 | Unit* target = GetCharm(); |
| 18664 | if(!target || !target->isPossessed()) |
| 18665 | return; |
| 18666 | |
| 18667 | // Remove area auras from possessed |
| 18668 | Unit::AuraMap& tAuras = target->GetAuras(); |
| 18669 | for(Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();) |
| 18670 | { |
| 18671 | if(itr->second && itr->second->IsAreaAura()) |
| 18672 | target->RemoveAura(itr); |
| 18673 | else |
| 18674 | ++itr; |
| 18675 | } |
| 18676 | |
| 18677 | RemovePossessedTarget(); |
| 18678 | |
| 18679 | if(target->GetTypeId() == TYPEID_PLAYER) |
| 18680 | ((Player*)target)->setFactionForRace(target->getRace()); |
| 18681 | else if(target->GetTypeId() == TYPEID_UNIT) |
| 18682 | { |
| 18683 | // Set creature to inactive in grid and place it back into the grid container |
| 18684 | Map* map = target->GetMap(); |
| 18685 | target->setActive(false); |
| 18686 | map->SwitchGridContainers((Creature*)target, false); |
| 18687 | |
| 18688 | if(((Creature*)target)->isPet()) |
| 18689 | { |
| 18690 | if(Unit* owner = target->GetOwner()) |
| 18691 | target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, owner->getFaction()); |
| 18692 | } else |
| 18693 | { |
| 18694 | if(CreatureInfo const* cInfo = ((Creature*)target)->GetCreatureInfo()) |
| 18695 | target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, cInfo->faction_A); |
| 18696 | } |
| 18697 | } |
| 18698 | |
| 18699 | target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5); |
| 18700 | target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); |
| 18701 | RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); |
| 18702 | SetUInt64Value(PLAYER_FARSIGHT, 0); |
| 18703 | |
| 18704 | // Remove pet spell action bar |
| 18705 | WorldPacket data(SMSG_PET_SPELLS, 8); |
| 18706 | data << uint64(0); |
| 18707 | m_session->SendPacket(&data); |
| 18708 | |
| 18709 | // Restore original view |
| 18710 | SetViewport(GetGUID(), true); |
| 18711 | if(target->GetTypeId() == TYPEID_PLAYER) |
| 18712 | ((Player*)target)->SetViewport(target->GetGUID(), true); |
| 18713 | else |
| 18714 | { |
| 18715 | if(((Creature*)target)->isPet()) |
| 18716 | { |
| 18717 | ((Pet*)target)->InitPetCreateSpells(); |
| 18718 | PetSpellInitialize(); |
| 18719 | } |
| 18720 | |
| 18721 | if (target->isAlive()) |
| 18722 | { |
| 18723 | // If we're still hostile to our target, continue attacking otherwise reset threat and go home |
| 18724 | if (target->getVictim()) |
| 18725 | { |
| 18726 | Unit* victim = target->getVictim(); |
| 18727 | FactionTemplateEntry const* t_faction = target->getFactionTemplateEntry(); |
| 18728 | FactionTemplateEntry const* v_faction = victim->getFactionTemplateEntry(); |
| 18729 | // Unit::IsHostileTo will always return true since the unit is always hostile to its victim |
| 18730 | if (t_faction && v_faction && !t_faction->IsHostileTo(*v_faction)) |
| 18731 | { |
| 18732 | // Stop combat and remove the target from the threat lists of all its victims |
| 18733 | target->CombatStop(); |
| 18734 | target->getHostilRefManager().deleteReferences(); |
| 18735 | target->DeleteThreatList(); |
| 18736 | target->GetMotionMaster()->Clear(); |
| 18737 | target->GetMotionMaster()->MoveTargetedHome(); |
| 18738 | } |
| 18739 | } |
| 18740 | else if (target->GetTypeId() == TYPEID_UNIT) |
| 18741 | { |
| 18742 | target->GetMotionMaster()->Clear(); |
| 18743 | target->GetMotionMaster()->MoveTargetedHome(); |
| 18744 | } |
| 18745 | |
| 18746 | // Add high amount of threat on the player |
| 18747 | if(target != GetPet() && attack) |
| 18748 | target->AddThreat(this, 1000000.0f); |
| 18749 | } |
| 18750 | // Delete the assigned possessed AI |
| 18751 | ((Creature*)target)->DeletePossessedAI(); |
| 18752 | } |
| 18753 | } |
| 18754 | |
| 18755 | void Player::SetViewport(uint64 guid, bool moveable) |
| 18756 | { |
| 18757 | WorldPacket data(SMSG_CLIENT_CONTROL_UPDATE, 8+1); |
| 18758 | data.appendPackGUID(guid); // Packed guid of object to set client's view to |
| 18759 | data << (moveable ? uint8(0x01) : uint8(0x00)); // 0 - can't move; 1 - can move |
| 18760 | m_session->SendPacket(&data); |
| 18761 | sLog.outDetail("Viewport for "I64FMT" (%s) changed to "I64FMT, GetGUID(), GetName(), guid); |