private void OnKill(Session session) { IsAlive = false; // This will determine if the derived type is a player var isDerivedPlayer = Guid.IsPlayer(); if (!isDerivedPlayer) { // Create and send the death notice string killMessage = $"{session.Player.Name} has killed {Name}."; var creatureDeathEvent = new GameEventDeathNotice(session, killMessage); session.Network.EnqueueSend(creatureDeathEvent); } // MovementEvent: (Hand-)Combat or in the case of smite: from Standing to Death // TODO: Check if the duration of the motion can somehow be computed UniversalMotion motionDeath = new UniversalMotion(MotionStance.Standing, new MotionItem(MotionCommand.Dead)); CurrentLandblock.EnqueueBroadcastMotion(this, motionDeath); // If the object is a creature, Remove it from from Landblock if (!isDerivedPlayer) { CurrentLandblock.RemoveWorldObject(Guid, false); } }
public override void OnCollideObject(WorldObject target) { if (!PhysicsObj.is_active()) { return; } //Console.WriteLine(string.Format("Projectile.OnCollideObject({0} - {1} || {2} - {3})", Guid.Full.ToString("X8"), Name, target.Guid.Full.ToString("X8"), target.Name)); if (ProjectileTarget == null || !ProjectileTarget.Equals(target)) { //Console.WriteLine("Unintended projectile target! (should be " + ProjectileTarget.Guid.Full.ToString("X8") + " - " + ProjectileTarget.Name + ")"); OnCollideEnvironment(); return; } // take damage var player = ProjectileSource as Player; if (player != null) { var damage = player.DamageTarget(target, this); if (damage > 0) { player.Session.Network.EnqueueSend(new GameMessageSound(Guid, Sound.Collision, 1.0f)); // todo: landblock broadcast? } } CurrentLandblock.RemoveWorldObject(Guid, false); PhysicsObj.set_active(false); }
private void LogOut_Final(bool skipAnimations = false) { if (CurrentLandblock != null) { if (skipAnimations) { CurrentLandblock?.RemoveWorldObject(Guid, false); SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); } else { var logout = new Motion(MotionStance.NonCombat, MotionCommand.LogOut); EnqueueBroadcastMotion(logout); EnqueueBroadcastPhysicsState(); var logoutChain = new ActionChain(); var motionTable = DatManager.PortalDat.ReadFromDat <MotionTable>((uint)MotionTableId); float logoutAnimationLength = motionTable.GetAnimationLength(MotionCommand.LogOut); logoutChain.AddDelaySeconds(logoutAnimationLength); // remove the player from landblock management -- after the animation has run logoutChain.AddAction(WorldManager.ActionQueue, () => { // If we're in the dying animation process, we cannot RemoveWorldObject and logout until that animation completes.. if (isInDeathProcess) { return; } CurrentLandblock?.RemoveWorldObject(Guid, false); SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); }); // close any open landblock containers (chests / corpses) if (LastOpenedContainerId != ObjectGuid.Invalid) { var container = CurrentLandblock.GetObject(LastOpenedContainerId) as Container; if (container != null) { container.Close(this); } } logoutChain.EnqueueChain(); } } else { SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); } }
private void FinalizeLogout() { CurrentLandblock?.RemoveWorldObject(Guid, false); SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); }
/// <summary> /// Do the player log out work.<para /> /// If you want to force a player to logout, use Session.LogOffPlayer(). /// </summary> public void LogOut(bool clientSessionTerminatedAbruptly = false) { if (Fellowship != null) { FellowshipQuit(false); } if (!clientSessionTerminatedAbruptly) { // Thie retail server sends a ChatRoomTracker 0x0295 first, then the status message, 0x028B. It does them one at a time for each individual channel. // The ChatRoomTracker message doesn't seem to change at all. // For the purpose of ACE, we simplify this process. var general = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "General"); var trade = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "Trade"); var lfg = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "LFG"); var roleplay = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "Roleplay"); Session.Network.EnqueueSend(general, trade, lfg, roleplay); } if (CurrentLandblock != null) { var logout = new Motion(MotionStance.NonCombat, MotionCommand.LogOut); EnqueueBroadcastMotion(logout); EnqueueBroadcastPhysicsState(); var logoutChain = new ActionChain(); var motionTable = DatManager.PortalDat.ReadFromDat <MotionTable>((uint)MotionTableId); float logoutAnimationLength = motionTable.GetAnimationLength(MotionCommand.LogOut); logoutChain.AddDelaySeconds(logoutAnimationLength); // remove the player from landblock management -- after the animation has run logoutChain.AddAction(this, () => { if (PlayerKillerStatus == PlayerKillerStatus.PKLite) { PlayerKillerStatus = PlayerKillerStatus.NPK; } CurrentLandblock?.RemoveWorldObject(Guid, false); SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); }); logoutChain.EnqueueChain(); } else { SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); } }
public ActionChain GetLogoutChain(bool clientSessionTerminatedAbruptly = false) { ActionChain logoutChain = new ActionChain(this, () => LogoutInternal(clientSessionTerminatedAbruptly)); var motionTable = DatManager.PortalDat.ReadFromDat <MotionTable>((uint)MotionTableId); float logoutAnimationLength = motionTable.GetAnimationLength(MotionCommand.LogOut); logoutChain.AddDelaySeconds(logoutAnimationLength); if (CurrentLandblock != null) { // remove the player from landblock management -- after the animation has run logoutChain.AddAction(this, () => CurrentLandblock.RemoveWorldObject(Guid, false)); } return(logoutChain); }
public override void OnCollideEnvironment() { if (!PhysicsObj.is_active()) { return; } //Console.WriteLine("Projectile.OnCollideEnvironment(" + Guid.Full.ToString("X8") + ")"); CurrentLandblock.RemoveWorldObject(Guid, false); PhysicsObj.set_active(false); var player = ProjectileSource as Player; if (player != null) { player.Session.Network.EnqueueSend(new GameMessageSystemChat("Your missile attack hit the environment.", ChatMessageType.Broadcast)); } }
/// <summary> /// Launches a projectile from player to target /// </summary> public float LaunchProjectile(WorldObject target) { var ammo = GetEquippedAmmo(); var arrow = WorldObjectFactory.CreateNewWorldObject(ammo.WeenieClassId); var origin = Location.ToGlobal(); origin.Z += Height; var dest = target.Location.ToGlobal(); dest.Z += target.Height / GetAimHeight(target); var speed = 35.0f; var dir = Vector3.Normalize(dest - origin); origin += dir * 2.0f; arrow.Velocity = GetProjectileVelocity(target, origin, dir, dest, speed, out var time); var loc = Location; origin = Position.FromGlobal(origin).Pos; arrow.Location = new Position(loc.LandblockId.Raw, origin.X, origin.Y, origin.Z, loc.Rotation.X, loc.Rotation.Y, loc.Rotation.Z, loc.RotationW); SetProjectilePhysicsState(arrow); LandblockManager.AddObject(arrow); CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessageScript(arrow.Guid, ACE.Entity.Enum.PlayScript.Launch, 1.0f)); var actionChain = new ActionChain(); actionChain.AddDelaySeconds(time); actionChain.AddAction(arrow, () => Session.Network.EnqueueSend(new GameMessageSound(arrow.Guid, Sound.Collision, 1.0f))); actionChain.AddAction(arrow, () => CurrentLandblock.RemoveWorldObject(arrow.Guid, false)); actionChain.EnqueueChain(); return(time); }
public void LogOut_Inner(bool clientSessionTerminatedAbruptly = false) { if (Fellowship != null) { FellowshipQuit(false); } if (IsTrading && TradePartner != null) { var tradePartner = PlayerManager.GetOnlinePlayer(TradePartner); if (tradePartner != null) { tradePartner.HandleActionCloseTradeNegotiations(); } } if (!clientSessionTerminatedAbruptly) { // Thie retail server sends a ChatRoomTracker 0x0295 first, then the status message, 0x028B. It does them one at a time for each individual channel. // The ChatRoomTracker message doesn't seem to change at all. // For the purpose of ACE, we simplify this process. var general = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "General"); var trade = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "Trade"); var lfg = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "LFG"); var roleplay = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "Roleplay"); Session.Network.EnqueueSend(general, trade, lfg, roleplay); } if (CurrentActiveCombatPet != null) { CurrentActiveCombatPet.Destroy(); } if (CurrentLandblock != null) { var logout = new Motion(MotionStance.NonCombat, MotionCommand.LogOut); EnqueueBroadcastMotion(logout); EnqueueBroadcastPhysicsState(); var logoutChain = new ActionChain(); var motionTable = DatManager.PortalDat.ReadFromDat <MotionTable>((uint)MotionTableId); float logoutAnimationLength = motionTable.GetAnimationLength(MotionCommand.LogOut); logoutChain.AddDelaySeconds(logoutAnimationLength); // remove the player from landblock management -- after the animation has run logoutChain.AddAction(this, () => { CurrentLandblock?.RemoveWorldObject(Guid, false); SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); }); // close any open landblock containers (chests / corpses) if (LastOpenedContainerId != ObjectGuid.Invalid) { var container = CurrentLandblock.GetObject(LastOpenedContainerId) as Container; if (container != null) { container.Close(this); } } logoutChain.EnqueueChain(); } else { SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); } }
public void LogOut_Inner(bool clientSessionTerminatedAbruptly = false) { IsBusy = true; IsLoggingOut = true; if (Fellowship != null) { FellowshipQuit(false); } if (IsTrading && TradePartner != ObjectGuid.Invalid) { var tradePartner = PlayerManager.GetOnlinePlayer(TradePartner); if (tradePartner != null) { tradePartner.HandleActionCloseTradeNegotiations(); } } if (!clientSessionTerminatedAbruptly) { if (PropertyManager.GetBool("use_turbine_chat").Item) { if (GetCharacterOption(CharacterOption.ListenToGeneralChat)) { LeaveTurbineChatChannel("General"); } if (GetCharacterOption(CharacterOption.ListenToTradeChat)) { LeaveTurbineChatChannel("Trade"); } if (GetCharacterOption(CharacterOption.ListenToLFGChat)) { LeaveTurbineChatChannel("LFG"); } if (GetCharacterOption(CharacterOption.ListenToRoleplayChat)) { LeaveTurbineChatChannel("Roleplay"); } if (GetCharacterOption(CharacterOption.ListenToAllegianceChat) && Allegiance != null) { LeaveTurbineChatChannel("Allegiance"); } if (GetCharacterOption(CharacterOption.ListenToSocietyChat) && Society != FactionBits.None) { LeaveTurbineChatChannel("Society"); } } } if (CurrentActivePet != null) { CurrentActivePet.Destroy(); } if (CurrentLandblock != null) { var logout = new Motion(MotionStance.NonCombat, MotionCommand.LogOut); EnqueueBroadcastMotion(logout); EnqueueBroadcastPhysicsState(); var logoutChain = new ActionChain(); var motionTable = DatManager.PortalDat.ReadFromDat <MotionTable>((uint)MotionTableId); float logoutAnimationLength = motionTable.GetAnimationLength(MotionCommand.LogOut); logoutChain.AddDelaySeconds(logoutAnimationLength); // remove the player from landblock management -- after the animation has run logoutChain.AddAction(this, () => { if (CurrentLandblock == null) { log.Debug($"0x{Guid}:{Name}.LogOut_Inner.logoutChain: CurrentLandblock is null, unable to remove from a landblock..."); if (Location != null) { log.Debug($"0x{Guid}:{Name}.LogOut_Inner.logoutChain: Location is not null, Location = {Location.ToLOCString()}"); } } CurrentLandblock?.RemoveWorldObject(Guid, false); SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); }); // close any open landblock containers (chests / corpses) if (LastOpenedContainerId != ObjectGuid.Invalid) { var container = CurrentLandblock.GetObject(LastOpenedContainerId) as Container; if (container != null) { container.Close(this); } } logoutChain.EnqueueChain(); } else { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: CurrentLandblock is null"); if (Location != null) { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Location is not null, Location = {Location.ToLOCString()}"); var validLoadedLandblock = LandblockManager.GetLandblock(Location.LandblockId, false); if (validLoadedLandblock.GetObject(Guid.Full) != null) { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Player is still on landblock, removing..."); validLoadedLandblock.RemoveWorldObject(Guid, false); } else { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Player is not found on the landblock Location references."); } } else { log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Location is null"); } SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); } }
/// <summary> /// Launches a projectile from player to target /// </summary> public WorldObject LaunchProjectile(WorldObject target, out float time) { var ammo = GetEquippedAmmo(); var arrow = WorldObjectFactory.CreateNewWorldObject(ammo.WeenieClassId); var origin = Location.ToGlobal(); origin.Z += Height; var dest = target.Location.ToGlobal(); dest.Z += target.Height / GetAimHeight(target); var speed = 35.0f; var dir = Vector3.Normalize(dest - origin); origin += dir * 2.0f; arrow.Velocity = GetProjectileVelocity(target, origin, dir, dest, speed, out time); var loc = Location; origin = Position.FromGlobal(origin).Pos; arrow.Location = new Position(loc.LandblockId.Raw, origin.X, origin.Y, origin.Z, loc.Rotation.X, loc.Rotation.Y, loc.Rotation.Z, loc.RotationW); SetProjectilePhysicsState(arrow); var actionChain = new ActionChain(); // TODO: Get correct aim level based on arrow velocity and add aim motion delay. var motion = new UniversalMotion(CurrentMotionState.Stance); motion.MovementData.CurrentStyle = (uint)CurrentMotionState.Stance; motion.MovementData.ForwardCommand = (uint)MotionCommand.AimLevel; CurrentMotionState = motion; actionChain.AddAction(this, () => DoMotion(motion)); //actionChain.AddDelaySeconds(animLength); actionChain.AddAction(this, () => LandblockManager.AddObject(arrow)); actionChain.AddAction(this, () => CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessagePickupEvent(ammo))); var player = this as Player; // TODO: Add support for monster ammo depletion. For now only players will use up ammo. if (player != null) { actionChain.AddAction(this, () => UpdateAmmoAfterLaunch(ammo)); } // Not sure why this would be needed but it is sent in retail pcaps. actionChain.AddAction(arrow, () => CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessageSetStackSize(arrow))); if (player != null) { actionChain.AddAction(arrow, () => CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessagePublicUpdatePropertyInt( arrow, PropertyInt.PlayerKillerStatus, (int)(player.PlayerKillerStatus ?? ACE.Entity.Enum.PlayerKillerStatus.NPK)))); } else { actionChain.AddAction(arrow, () => CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessagePublicUpdatePropertyInt( arrow, PropertyInt.PlayerKillerStatus, (int)ACE.Entity.Enum.PlayerKillerStatus.Creature))); } actionChain.AddAction(arrow, () => CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessageScript(arrow.Guid, ACE.Entity.Enum.PlayScript.Launch, 0f))); actionChain.AddDelaySeconds(time); // todo: landblock broadcast? if (player != null) { actionChain.AddAction(arrow, () => player.Session.Network.EnqueueSend(new GameMessageSound(arrow.Guid, Sound.Collision, 1.0f))); } actionChain.AddAction(arrow, () => CurrentLandblock.RemoveWorldObject(arrow.Guid, false)); actionChain.EnqueueChain(); return(arrow); }