public void UpdateCharmAI() { if (IsCharmed()) { UnitAI newAI = null; if (IsPlayer()) { Unit charmer = GetCharmer(); if (charmer != null) { // first, we check if the creature's own AI specifies an override playerai for its owned players Creature creatureCharmer = charmer.ToCreature(); if (creatureCharmer != null) { CreatureAI charmerAI = creatureCharmer.GetAI(); if (charmerAI != null) { newAI = charmerAI.GetAIForCharmedPlayer(ToPlayer()); } } else { Log.outError(LogFilter.Misc, $"Attempt to assign charm AI to player {GetGUID()} who is charmed by non-creature {GetCharmerGUID()}."); } } if (newAI == null) // otherwise, we default to the generic one { newAI = new SimpleCharmedPlayerAI(ToPlayer()); } } else { Cypher.Assert(IsCreature()); if (IsPossessed() || IsVehicle()) { newAI = new PossessedAI(ToCreature()); } else { newAI = new PetAI(ToCreature()); } } Cypher.Assert(newAI != null); SetAI(newAI); newAI.OnCharmed(true); } else { RestoreDisabledAI(); // Hack: this is required because we want to call OnCharmed(true) on the restored AI RefreshAI(); UnitAI ai = GetAI(); if (ai != null) { ai.OnCharmed(true); } } }
public void RemoveCharmedBy(Unit charmer) { if (!IsCharmed()) { return; } if (charmer) { Cypher.Assert(charmer == GetCharmer()); } else { charmer = GetCharmer(); } Cypher.Assert(charmer); CharmType type; if (HasUnitState(UnitState.Possessed)) { type = CharmType.Possess; } else if (charmer && charmer.IsOnVehicle(this)) { type = CharmType.Vehicle; } else { type = CharmType.Charm; } CastStop(); CombatStop(); // @todo CombatStop(true) may cause crash (interrupt spells) if (_oldFactionId != 0) { SetFaction(_oldFactionId); _oldFactionId = 0; } else { RestoreFaction(); } ///@todo Handle SLOT_IDLE motion resume GetMotionMaster().InitializeDefault(); // Vehicle should not attack its passenger after he exists the seat if (type != CharmType.Vehicle) { LastCharmerGUID = charmer.GetGUID(); } Cypher.Assert(type != CharmType.Possess || charmer.IsTypeId(TypeId.Player)); Cypher.Assert(type != CharmType.Vehicle || (IsTypeId(TypeId.Unit) && IsVehicle())); charmer.SetCharm(this, false); Player playerCharmer = charmer.ToPlayer(); if (playerCharmer) { switch (type) { case CharmType.Vehicle: playerCharmer.SetClientControl(this, false); playerCharmer.SetClientControl(charmer, true); RemoveUnitFlag(UnitFlags.Possessed); break; case CharmType.Possess: ClearUnitState(UnitState.Possessed); playerCharmer.SetClientControl(this, false); playerCharmer.SetClientControl(charmer, true); charmer.RemoveUnitFlag(UnitFlags.RemoveClientControl); RemoveUnitFlag(UnitFlags.Possessed); break; case CharmType.Charm: if (IsTypeId(TypeId.Unit) && charmer.GetClass() == Class.Warlock) { CreatureTemplate cinfo = ToCreature().GetCreatureTemplate(); if (cinfo != null && cinfo.CreatureType == CreatureType.Demon) { SetClass((Class)cinfo.UnitClass); if (GetCharmInfo() != null) { GetCharmInfo().SetPetNumber(0, true); } else { Log.outError(LogFilter.Unit, "Aura:HandleModCharm: target={0} with typeid={1} has a charm aura but no charm info!", GetGUID(), GetTypeId()); } } } break; case CharmType.Convert: break; } } Player player = ToPlayer(); if (player != null) { player.SetClientControl(this, true); } if (playerCharmer && this != charmer.GetFirstControlled()) { playerCharmer.SendRemoveControlBar(); } // a guardian should always have charminfo if (!IsGuardian()) { DeleteCharmInfo(); } // reset confused movement for example ApplyControlStatesIfNeeded(); if (!IsPlayer() || charmer.IsCreature()) { UnitAI charmedAI = GetAI(); if (charmedAI != null) { charmedAI.OnCharmed(false); // AI will potentially schedule a charm ai update } else { ScheduleAIChange(); } } }
public bool SetCharmedBy(Unit charmer, CharmType type, AuraApplication aurApp = null) { if (!charmer) { return(false); } // dismount players when charmed if (IsTypeId(TypeId.Player)) { RemoveAurasByType(AuraType.Mounted); } if (charmer.IsTypeId(TypeId.Player)) { charmer.RemoveAurasByType(AuraType.Mounted); } Cypher.Assert(type != CharmType.Possess || charmer.IsTypeId(TypeId.Player)); Cypher.Assert((type == CharmType.Vehicle) == (GetVehicleKit() && GetVehicleKit().IsControllableVehicle())); Log.outDebug(LogFilter.Unit, "SetCharmedBy: charmer {0} (GUID {1}), charmed {2} (GUID {3}), type {4}.", charmer.GetEntry(), charmer.GetGUID().ToString(), GetEntry(), GetGUID().ToString(), type); if (this == charmer) { Log.outFatal(LogFilter.Unit, "Unit:SetCharmedBy: Unit {0} (GUID {1}) is trying to charm itself!", GetEntry(), GetGUID().ToString()); return(false); } if (IsTypeId(TypeId.Player) && ToPlayer().GetTransport()) { Log.outFatal(LogFilter.Unit, "Unit:SetCharmedBy: Player on transport is trying to charm {0} (GUID {1})", GetEntry(), GetGUID().ToString()); return(false); } // Already charmed if (!GetCharmerGUID().IsEmpty()) { Log.outFatal(LogFilter.Unit, "Unit:SetCharmedBy: {0} (GUID {1}) has already been charmed but {2} (GUID {3}) is trying to charm it!", GetEntry(), GetGUID().ToString(), charmer.GetEntry(), charmer.GetGUID().ToString()); return(false); } CastStop(); CombatStop(); // @todo CombatStop(true) may cause crash (interrupt spells) Player playerCharmer = charmer.ToPlayer(); // Charmer stop charming if (playerCharmer) { playerCharmer.StopCastingCharm(); playerCharmer.StopCastingBindSight(); } // Charmed stop charming if (IsTypeId(TypeId.Player)) { ToPlayer().StopCastingCharm(); ToPlayer().StopCastingBindSight(); } // StopCastingCharm may remove a possessed pet? if (!IsInWorld) { Log.outFatal(LogFilter.Unit, "Unit:SetCharmedBy: {0} (GUID {1}) is not in world but {2} (GUID {3}) is trying to charm it!", GetEntry(), GetGUID().ToString(), charmer.GetEntry(), charmer.GetGUID().ToString()); return(false); } // charm is set by aura, and aura effect remove handler was called during apply handler execution // prevent undefined behaviour if (aurApp != null && aurApp.GetRemoveMode() != 0) { return(false); } _oldFactionId = GetFaction(); SetFaction(charmer.GetFaction()); // Pause any Idle movement PauseMovement(0, 0, false); // Remove any active voluntary movement GetMotionMaster().Clear(MovementGeneratorPriority.Normal); // Stop any remaining spline, if no involuntary movement is found Func <MovementGenerator, bool> criteria = movement => movement.Priority == MovementGeneratorPriority.Highest; if (!GetMotionMaster().HasMovementGenerator(criteria)) { StopMoving(); } // Set charmed charmer.SetCharm(this, true); Player player = ToPlayer(); if (player) { if (player.IsAFK()) { player.ToggleAFK(); } player.SetClientControl(this, false); } // charm is set by aura, and aura effect remove handler was called during apply handler execution // prevent undefined behaviour if (aurApp != null && aurApp.GetRemoveMode() != 0) { return(false); } // Pets already have a properly initialized CharmInfo, don't overwrite it. if (type != CharmType.Vehicle && GetCharmInfo() == null) { InitCharmInfo(); if (type == CharmType.Possess) { GetCharmInfo().InitPossessCreateSpells(); } else { GetCharmInfo().InitCharmCreateSpells(); } } if (playerCharmer) { switch (type) { case CharmType.Vehicle: AddUnitFlag(UnitFlags.Possessed); playerCharmer.SetClientControl(this, true); playerCharmer.VehicleSpellInitialize(); break; case CharmType.Possess: AddUnitFlag(UnitFlags.Possessed); charmer.AddUnitFlag(UnitFlags.RemoveClientControl); playerCharmer.SetClientControl(this, true); playerCharmer.PossessSpellInitialize(); AddUnitState(UnitState.Possessed); break; case CharmType.Charm: if (IsTypeId(TypeId.Unit) && charmer.GetClass() == Class.Warlock) { CreatureTemplate cinfo = ToCreature().GetCreatureTemplate(); if (cinfo != null && cinfo.CreatureType == CreatureType.Demon) { // to prevent client crash SetClass(Class.Mage); // just to enable stat window if (GetCharmInfo() != null) { GetCharmInfo().SetPetNumber(Global.ObjectMgr.GeneratePetNumber(), true); } // if charmed two demons the same session, the 2nd gets the 1st one's name SetPetNameTimestamp((uint)GameTime.GetGameTime()); // cast can't be helped } } playerCharmer.CharmSpellInitialize(); break; default: case CharmType.Convert: break; } } AddUnitState(UnitState.Charmed); if (!IsPlayer() || !charmer.IsPlayer()) { // AI will schedule its own change if appropriate UnitAI ai = GetAI(); if (ai != null) { ai.OnCharmed(false); } else { ScheduleAIChange(); } } return(true); }