public static void HandleRebuff(Session session, params string[] parameters) { var player = session.Player; var realm = RealmManager.GetRealm(player.HomeRealm); if (realm == null) { return; } if (!realm.StandardRules.GetProperty(RealmPropertyBool.IsDuelingRealm)) { return; } var ts = player.GetProperty(PropertyInt.LastRebuffTimestamp); if (ts != null) { var timesince = (int)Time.GetUnixTime() - ts.Value; if (timesince < 180) { session.Network.EnqueueSend(new GameMessageSystemChat($"You may use this command again in {180 - timesince}s.", ChatMessageType.Broadcast)); return; } } player.SetProperty(PropertyInt.LastRebuffTimestamp, (int)Time.GetUnixTime()); player.CreateSentinelBuffPlayers(new Player[] { player }, true); }
private void ApplyJob(RealmLinkJob job) { foreach (var link in job.Links) { if (random.NextDouble() < link.Probability) { var template = RealmManager.GetRealm(link.RulesetIDToApply).RulesetTemplate; ComposeFrom(template, true); return; } } }
/// <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(DamageHistoryInfo lastDamager, DamageHistoryInfo topDamager) { if (topDamager?.Guid == Guid && IsPKType) { var topDamagerOther = DamageHistory.GetTopDamager(false); if (topDamagerOther != null && topDamagerOther.IsPlayer) { topDamager = topDamagerOther; } } UpdateVital(Health, 0); NumDeaths++; suicideInProgress = false; if (CombatMode == CombatMode.Magic && MagicState.IsCasting) { FailCast(false); } // TODO: instead of setting IsBusy here, // eventually all of the places that check for states such as IsBusy || Teleporting // might want to use a common function, and IsDead should return a separate error IsBusy = true; // killer = top damager for looting rights if (topDamager != null) { KillerId = topDamager.Guid.Full; } // broadcast death animation var deathAnim = new Motion(MotionStance.NonCombat, MotionCommand.Dead); EnqueueBroadcastMotion(deathAnim); // 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 msgNumDeaths = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.NumDeaths, NumDeaths); // send network messages for player death Session.Network.EnqueueSend(msgHealthUpdate, msgNumDeaths); if (lastDamager?.Guid == Guid) // suicide { var msgSelfInflictedDeath = new GameEventWeenieError(Session, WeenieError.YouKilledYourself); Session.Network.EnqueueSend(msgSelfInflictedDeath); } // update vitae // players who died in a PKLite fight do not accrue vitae var duelRealm = RealmManager.GetRealm(HomeRealm)?.StandardRules?.GetProperty(RealmPropertyBool.IsDuelingRealm) == true || RealmRuleset?.GetProperty(RealmPropertyBool.IsDuelingRealm) == true; if (!duelRealm && !IsPKLiteDeath(topDamager)) { InflictVitaePenalty(); } if (!duelRealm && IsPKDeath(topDamager) || AugmentationSpellsRemainPastDeath == 0) { var msgPurgeEnchantments = new GameEventMagicPurgeEnchantments(Session); EnchantmentManager.RemoveAllEnchantments(); Session.Network.EnqueueSend(msgPurgeEnchantments); } else { Session.Network.EnqueueSend(new GameMessageSystemChat("Your augmentation prevents the tides of death from ripping away your current enchantments!", ChatMessageType.Broadcast)); } // 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); dieChain.AddAction(this, () => { if (!duelRealm) { CreateCorpse(topDamager); } ThreadSafeTeleportOnDeath(); // enter portal space if (IsPKDeath(topDamager) || IsPKLiteDeath(topDamager)) { SetMinimumTimeSincePK(); } IsBusy = false; }); dieChain.EnqueueChain(); }