Exemplo n.º 1
0
        /// <summary>
        /// Called when the player enters portal space after dying
        /// </summary>
        public void ThreadSafeTeleportOnDeath()
        {
            // teleport to sanctuary or best location
            var newPosition = Sanctuary ?? Instantiation ?? Location;

            WorldManager.ThreadSafeTeleport(this, newPosition, new ActionEventDelegate(() =>
            {
                // Stand back up
                SetCombatMode(CombatMode.NonCombat);

                SetLifestoneProtection();

                var teleportChain = new ActionChain();
                if (!IsLoggingOut) // If we're in the process of logging out, we skip the delay
                {
                    teleportChain.AddDelaySeconds(3.0f);
                }
                teleportChain.AddAction(this, () =>
                {
                    // currently happens while in portal space
                    var newHealth  = (uint)Math.Round(Health.MaxValue * 0.75f);
                    var newStamina = (uint)Math.Round(Stamina.MaxValue * 0.75f);
                    var newMana    = (uint)Math.Round(Mana.MaxValue * 0.75f);

                    var msgHealthUpdate  = new GameMessagePrivateUpdateAttribute2ndLevel(this, Vital.Health, newHealth);
                    var msgStaminaUpdate = new GameMessagePrivateUpdateAttribute2ndLevel(this, Vital.Stamina, newStamina);
                    var msgManaUpdate    = new GameMessagePrivateUpdateAttribute2ndLevel(this, Vital.Mana, newMana);

                    UpdateVital(Health, newHealth);
                    UpdateVital(Stamina, newStamina);
                    UpdateVital(Mana, newMana);

                    Session.Network.EnqueueSend(msgHealthUpdate, msgStaminaUpdate, msgManaUpdate);

                    // reset damage history for this player
                    DamageHistory.Reset();

                    OnHealthUpdate();

                    IsInDeathProcess = false;

                    if (IsLoggingOut)
                    {
                        LogOut_Final(true);
                    }
                });

                teleportChain.EnqueueChain();
            }));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Called when a player dies, in conjunction with Die()
        /// </summary>
        /// <param name="lastDamager">The last damager that landed the death blow</param>
        /// <param name="damageType">The damage type for the death message</param>
        public override DeathMessage OnDeath(WorldObject lastDamager, DamageType damageType, bool criticalHit = false)
        {
            var deathMessage = base.OnDeath(lastDamager, damageType, criticalHit);

            var playerMsg    = string.Format(deathMessage.Victim, Name, lastDamager.Name);
            var msgYourDeath = new GameEventYourDeath(Session, playerMsg);

            Session.Network.EnqueueSend(msgYourDeath);

            // broadcast to nearby players
            var nearbyMsg     = string.Format(deathMessage.Broadcast, Name, lastDamager.Name);
            var broadcastMsg  = new GameMessageSystemChat(nearbyMsg, ChatMessageType.Broadcast);
            var nearbyPlayers = EnqueueBroadcast(false, broadcastMsg);

            var excludePlayers = nearbyPlayers.ToList();

            excludePlayers.Add(this);   // exclude self

            // if the player's lifestone is in a different landblock, also broadcast their demise to that landblock
            if (Sanctuary != null && Location.Landblock != Sanctuary.Landblock)
            {
                // ActionBroadcastKill might not work if other players around lifestone aren't aware of this player yet...
                // this existing broadcast method is also based on the current visible objects to the player,
                // and the player hasn't entered portal space or teleported back to the lifestone yet, so this doesn't work
                //ActionBroadcastKill(nearbyMsg, Guid, lastDamager.Guid);

                // instead, we get all of the players in the lifestone landblock + adjacent landblocks,
                // and possibly limit that to some radius around the landblock?
                var lifestoneBlock = LandblockManager.GetLandblock(new LandblockId(Sanctuary.Landblock << 16 | 0xFFFF), true);
                lifestoneBlock.EnqueueBroadcast(excludePlayers, true, broadcastMsg);
            }

            // reset damage history for this player
            DamageHistory.Reset();

            return(deathMessage);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Called when the player enters portal space after dying
        /// </summary>
        public void TeleportOnDeath()
        {
            // teleport to sanctuary or best location
            var newPosition = Sanctuary ?? LastPortal ?? Location;

            Teleport(newPosition);

            // Stand back up
            SetCombatMode(CombatMode.NonCombat);

            var teleportChain = new ActionChain();

            teleportChain.AddDelaySeconds(3.0f);
            teleportChain.AddAction(this, () =>
            {
                // currently happens while in portal space
                var newHealth  = (uint)Math.Round(Health.MaxValue * 0.75f);
                var newStamina = (uint)Math.Round(Stamina.MaxValue * 0.75f);
                var newMana    = (uint)Math.Round(Mana.MaxValue * 0.75f);

                var msgHealthUpdate  = new GameMessagePrivateUpdateAttribute2ndLevel(this, Vital.Health, newHealth);
                var msgStaminaUpdate = new GameMessagePrivateUpdateAttribute2ndLevel(this, Vital.Stamina, newStamina);
                var msgManaUpdate    = new GameMessagePrivateUpdateAttribute2ndLevel(this, Vital.Mana, newMana);

                UpdateVital(Health, newHealth);
                UpdateVital(Stamina, newStamina);
                UpdateVital(Mana, newMana);

                Session.Network.EnqueueSend(msgHealthUpdate, msgStaminaUpdate, msgManaUpdate);

                // reset damage history for this player
                DamageHistory.Reset();
            });

            teleportChain.EnqueueChain();
        }
Exemplo n.º 4
0
        /// <summary>
        /// Broadcasts the player death animation, updates vitae, and sends network messages for player death
        /// Queues the action to call TeleportOnDeath and enter portal space soon
        /// </summary>
        protected override void Die(WorldObject lastDamager, WorldObject topDamager)
        {
            UpdateVital(Health, 0);
            NumDeaths++;
            DeathLevel  = Level; // for calculating vitae XP
            VitaeCpPool = 0;     // reset vitae XP earned

            // killer = top damager for looting rights
            if (topDamager != null)
            {
                Killer = topDamager.Guid.Full;
            }

            // broadcast death animation
            var deathAnim = new UniversalMotion(MotionStance.NonCombat, new MotionItem(MotionCommand.Dead));

            EnqueueBroadcastMotion(deathAnim);

            // killer death message = last damager
            var killerMsg           = lastDamager != null ? " to " + lastDamager.Name : "";
            var currentDeathMessage = $"died{killerMsg}.";

            // create network messages for player death
            var msgHealthUpdate = new GameMessagePrivateUpdateAttribute2ndLevel(this, Vital.Health, 0);

            // TODO: death sounds? seems to play automatically in client
            // var msgDeathSound = new GameMessageSound(Guid, Sound.Death1, 1.0f);
            var msgYourDeath         = new GameEventYourDeath(Session, $"You have {currentDeathMessage}");
            var msgNumDeaths         = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.NumDeaths, NumDeaths ?? 0);
            var msgDeathLevel        = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.DeathLevel, DeathLevel ?? 0);
            var msgVitaeCpPool       = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.VitaeCpPool, VitaeCpPool.Value);
            var msgPurgeEnchantments = new GameEventPurgeAllEnchantments(Session);

            // update vitae
            var vitae = EnchantmentManager.UpdateVitae();

            var spellID             = (uint)Network.Enum.Spell.Vitae;
            var spellBase           = DatManager.PortalDat.SpellTable.Spells[spellID];
            var spell               = DatabaseManager.World.GetCachedSpell(spellID);
            var vitaeEnchantment    = new Enchantment(this, Guid, spellID, (double)spell.Duration, 0, spell.StatModType, vitae);
            var msgVitaeEnchantment = new GameEventMagicUpdateEnchantment(Session, vitaeEnchantment);

            // send network messages for player death
            Session.Network.EnqueueSend(msgHealthUpdate, msgYourDeath, msgNumDeaths, msgDeathLevel, msgVitaeCpPool, msgPurgeEnchantments, msgVitaeEnchantment);

            // wait for the death animation to finish
            var dieChain   = new ActionChain();
            var animLength = DatManager.PortalDat.ReadFromDat <MotionTable>(MotionTableId).GetAnimationLength(MotionCommand.Dead);

            dieChain.AddDelaySeconds(animLength + 1.0f);

            // enter portal space
            dieChain.AddAction(this, CreateCorpse);
            dieChain.AddAction(this, TeleportOnDeath);
            dieChain.EnqueueChain();

            // if the player's lifestone is in a different landblock, also broadcast their demise to that landblock
            if (Sanctuary != null && Location.Landblock != Sanctuary.Landblock)
            {
                var killerGuid = lastDamager != null ? lastDamager.Guid : Guid;
                ActionBroadcastKill($"{Name} has {currentDeathMessage}", Guid, killerGuid);
            }
            DamageHistory.Reset();
        }