using System; using System.Collections.Generic; using System.Text; using Server.Gumps; using Server.Items; using Server.Mobiles; using Server.Network; using Server.Targeting; namespace Server.Engines.ConPVP { public sealed class CTFBoard : Item { public CTFTeamInfo m_TeamInfo; [Constructible] public CTFBoard() : base(7774) => Movable = false; public CTFBoard(Serial serial) : base(serial) { } public override string DefaultName => "scoreboard"; public override void OnDoubleClick(Mobile from) { if (m_TeamInfo?.Game != null) { from.CloseGump(); from.SendGump(new CTFBoardGump(from, m_TeamInfo.Game)); } } public override void Serialize(GenericWriter writer) { base.Serialize(writer); writer.Write(0); } public override void Deserialize(GenericReader reader) { base.Deserialize(reader); int version = reader.ReadInt(); } } public class CTFBoardGump : Gump { private const int LabelColor32 = 0xFFFFFF; private const int BlackColor32 = 0x000000; private CTFGame m_Game; public CTFBoardGump(Mobile mob, CTFGame game, CTFTeamInfo section = null) : base(60, 60) { m_Game = game; CTFTeamInfo ourTeam = game.GetTeamInfo(mob); List entries = new List(); if (section == null) for (int i = 0; i < game.Context.Participants.Count; ++i) { CTFTeamInfo teamInfo = game.Controller.TeamInfo[i % 8]; if (teamInfo?.Flag == null) continue; entries.Add(teamInfo); } else foreach (CTFPlayerInfo player in section.Players.Values) if (player.Score > 0) entries.Add(player); entries.Sort(delegate(IRankedCTF a, IRankedCTF b) { return b.Score - a.Score; }); int height = 0; if (section == null) height = 73 + entries.Count * 75 + 28; Closable = false; AddPage(0); AddBackground(1, 1, 398, height, 3600); AddImageTiled(16, 15, 369, height - 29, 3604); for (int i = 0; i < entries.Count; i += 1) AddImageTiled(22, 58 + i * 75, 357, 70, 0x2430); AddAlphaRegion(16, 15, 369, height - 29); AddImage(215, -45, 0xEE40); //AddImage( 330, 141, 0x8BA ); AddBorderedText(22, 22, 294, 20, Center("CTF Scoreboard"), LabelColor32, BlackColor32); AddImageTiled(32, 50, 264, 1, 9107); AddImageTiled(42, 52, 264, 1, 9157); if (section == null) for (int i = 0; i < entries.Count; ++i) { CTFTeamInfo teamInfo = entries[i] as CTFTeamInfo; AddImage(30, 70 + i * 75, 10152); AddImage(30, 85 + i * 75, 10151); AddImage(30, 100 + i * 75, 10151); AddImage(30, 106 + i * 75, 10154); AddImage(24, 60 + i * 75, teamInfo == ourTeam ? 9730 : 9727, teamInfo.Color - 1); int nameColor = LabelColor32; int borderColor = BlackColor32; switch (teamInfo.Color) { case 0x47E: nameColor = 0xFFFFFF; break; case 0x4F2: nameColor = 0x3399FF; break; case 0x4F7: nameColor = 0x33FF33; break; case 0x4FC: nameColor = 0xFF00FF; break; case 0x021: nameColor = 0xFF3333; break; case 0x01A: nameColor = 0xFF66FF; break; case 0x455: nameColor = 0x333333; borderColor = 0xFFFFFF; break; } AddBorderedText(60, 65 + i * 75, 250, 20, $"{LadderGump.Rank(1 + i)}: {teamInfo.Name} Team", nameColor, borderColor); AddBorderedText(50 + 10, 85 + i * 75, 100, 20, "Score:", 0xFFC000, BlackColor32); AddBorderedText(50 + 15, 105 + i * 75, 100, 20, teamInfo.Score.ToString("N0"), 0xFFC000, BlackColor32); AddBorderedText(110 + 10, 85 + i * 75, 100, 20, "Kills:", 0xFFC000, BlackColor32); AddBorderedText(110 + 15, 105 + i * 75, 100, 20, teamInfo.Kills.ToString("N0"), 0xFFC000, BlackColor32); AddBorderedText(160 + 10, 85 + i * 75, 100, 20, "Captures:", 0xFFC000, BlackColor32); AddBorderedText(160 + 15, 105 + i * 75, 100, 20, teamInfo.Captures.ToString("N0"), 0xFFC000, BlackColor32); CTFPlayerInfo pl = teamInfo.Leader; AddBorderedText(235 + 10, 85 + i * 75, 250, 20, "Leader:", 0xFFC000, BlackColor32); if (pl != null) AddBorderedText(235 + 15, 105 + i * 75, 250, 20, pl.Player.Name, 0xFFC000, BlackColor32); } AddButton(314, height - 42, 247, 248, 1); } public string Center(string text) => $"
{text}
"; public string Color(string text, int color) => $"{text}"; private void AddBorderedText(int x, int y, int width, int height, string text, int color, int borderColor) { AddColoredText(x - 1, y - 1, width, height, text, borderColor); AddColoredText(x - 1, y + 1, width, height, text, borderColor); AddColoredText(x + 1, y - 1, width, height, text, borderColor); AddColoredText(x + 1, y + 1, width, height, text, borderColor); AddColoredText(x, y, width, height, text, color); } private void AddColoredText(int x, int y, int width, int height, string text, int color) { if (color == 0) AddHtml(x, y, width, height, text); else AddHtml(x, y, width, height, Color(text, color)); } } public sealed class CTFFlag : Item { public Mobile m_Fragger; public DateTime m_FragTime; private int m_ReturnCount; public Mobile m_Returner; public DateTime m_ReturnTime; private Timer m_ReturnTimer; public CTFTeamInfo m_TeamInfo; [Constructible] public CTFFlag() : base(5643) => Movable = false; public CTFFlag(Serial serial) : base(serial) { } public override string DefaultName => "old people cookies"; public override void OnDoubleClick(Mobile from) { if (m_TeamInfo?.Game != null) { CTFTeamInfo ourTeam = m_TeamInfo; CTFTeamInfo useTeam = m_TeamInfo.Game.GetTeamInfo(from); if (ourTeam == null || useTeam == null) return; if (IsChildOf(from.Backpack)) { from.BeginTarget(1, false, TargetFlags.None, Flag_OnTarget); } else if (!from.InRange(this, 1) || !from.InLOS(this)) { from.LocalOverheadMessage(MessageType.Regular, 0x26, 1019045); // I can't reach that } else if (ourTeam == useTeam) { if (Location == m_TeamInfo.Origin && Map == m_TeamInfo.Game.Facet) { from.Send(new UnicodeMessage(Serial, ItemID, MessageType.Regular, 0x3B2, 3, "ENU", Name, "Touch me not for I am chaste.")); } else { CTFPlayerInfo playerInfo = useTeam[from]; if (playerInfo != null) playerInfo.Score += 4; // return m_Returner = from; m_ReturnTime = DateTime.UtcNow; SendHome(); from.LocalOverheadMessage(MessageType.Regular, 0x59, false, "You returned the cookies!"); m_TeamInfo.Game.Alert("The {1} cookies have been returned by {0}.", from.Name, ourTeam.Name); } } else if (!from.PlaceInBackpack(this)) { from.LocalOverheadMessage(MessageType.Regular, 0x26, false, "I can't hold that."); } else { from.RevealingAction(); from.LocalOverheadMessage(MessageType.Regular, 0x59, false, "You stole the cookies!"); m_TeamInfo.Game.Alert("The {1} cookies have been stolen by {0} ({2}).", from.Name, ourTeam.Name, useTeam.Name); BeginCountdown(120); } } } public override void Delete() { if (Parent != null) { SendHome(); return; } base.Delete(); } public void DropTo(Mobile mob, Mobile killer) { m_Fragger = killer; m_FragTime = DateTime.UtcNow; if (mob != null) { MoveToWorld(new Point3D(mob.X, mob.Y, mob.Z + 2), mob.Map); m_ReturnCount = Math.Min(m_ReturnCount, 10); } else { SendHome(); } } private void StopCountdown() { m_ReturnTimer?.Stop(); m_ReturnTimer = null; } private void BeginCountdown(int returnCount) { StopCountdown(); m_ReturnTimer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0), Countdown_OnTick); m_ReturnCount = returnCount; } private void Countdown_OnTick() { Mobile owner = RootParent as Mobile; switch (m_ReturnCount) { case 60: case 30: case 15: case 10: case 5: case 4: case 3: case 2: case 1: { owner?.SendMessage(0x26, "You have {0} {1} to capture the cookies!", m_ReturnCount, m_ReturnCount == 1 ? "second" : "seconds"); break; } case 0: { if (owner != null) { owner.SendMessage(0x26, "You have taken too long to capture the cookies!"); owner.Kill(); } SendHome(); m_TeamInfo?.Game?.Alert("The {0} cookies have been returned.", m_TeamInfo.Name); return; } } --m_ReturnCount; } private void Flag_OnTarget(Mobile from, object obj) { if (m_TeamInfo == null) return; if (!IsChildOf(from.Backpack)) return; CTFTeamInfo ourTeam = m_TeamInfo; CTFTeamInfo useTeam = m_TeamInfo.Game.GetTeamInfo(from); if (obj is CTFFlag) { if (obj == useTeam.Flag) { from.LocalOverheadMessage(MessageType.Regular, 0x59, false, "You captured the cookies!"); m_TeamInfo.Game.Alert("{0} captured the {1} cookies!", from.Name, ourTeam.Name); SendHome(); CTFPlayerInfo playerInfo = useTeam[from]; if (playerInfo != null) { playerInfo.Captures += 1; playerInfo.Score += 50; // capture CTFFlag teamFlag = useTeam.Flag; if (teamFlag.m_Fragger != null && DateTime.UtcNow < teamFlag.m_FragTime + TimeSpan.FromSeconds(5.0) && m_TeamInfo.Game.GetTeamInfo(teamFlag.m_Fragger) == useTeam) { CTFPlayerInfo assistInfo = useTeam[teamFlag.m_Fragger]; if (assistInfo != null) assistInfo.Score += 6; // frag assist } if (teamFlag.m_Returner != null && DateTime.UtcNow < teamFlag.m_ReturnTime + TimeSpan.FromSeconds(5.0)) { CTFPlayerInfo assistInfo = useTeam[teamFlag.m_Returner]; if (assistInfo != null) assistInfo.Score += 4; // return assist } } } else { from.LocalOverheadMessage(MessageType.Regular, 0x26, false, "Those are not my cookies."); } } else if (obj is Mobile passTo) { CTFTeamInfo passTeam = m_TeamInfo.Game.GetTeamInfo(passTo); if (passTo == from) from.LocalOverheadMessage(MessageType.Regular, 0x26, false, "I can't pass to them."); else if (passTeam == useTeam && passTo.PlaceInBackpack(this)) passTo.LocalOverheadMessage(MessageType.Regular, 0x59, false, $"{from.Name} has passed you the cookies!"); else from.LocalOverheadMessage(MessageType.Regular, 0x26, false, "I can't pass to them."); } } public void SendHome() { StopCountdown(); if (m_TeamInfo == null) return; MoveToWorld(m_TeamInfo.Origin, m_TeamInfo.Game.Facet); } private Mobile FindOwner(IEntity parent) { if (parent is Item item) return item.RootParent as Mobile; if (parent is Mobile mobile) return mobile; return null; } public override void OnAdded(IEntity parent) { base.OnAdded(parent); Mobile mob = FindOwner(parent); if (mob != null) mob.SolidHueOverride = 0x4001; } public override void OnRemoved(IEntity parent) { base.OnRemoved(parent); Mobile mob = FindOwner(parent); if (mob != null) mob.SolidHueOverride = m_TeamInfo?.Game.GetColor(mob) ?? -1; } public override void Serialize(GenericWriter writer) { base.Serialize(writer); writer.Write(0); } public override void Deserialize(GenericReader reader) { base.Deserialize(reader); int version = reader.ReadInt(); } } public interface IRankedCTF { int Kills{ get; } int Captures{ get; } int Score{ get; } string Name{ get; } } public sealed class CTFPlayerInfo : IRankedCTF { private int m_Captures; private int m_Kills; private int m_Score; private CTFTeamInfo m_TeamInfo; public CTFPlayerInfo(CTFTeamInfo teamInfo, Mobile player) { m_TeamInfo = teamInfo; Player = player; } public Mobile Player{ get; } string IRankedCTF.Name => Player.Name; public int Kills { get => m_Kills; set { m_TeamInfo.Kills += value - m_Kills; m_Kills = value; } } public int Captures { get => m_Captures; set { m_TeamInfo.Captures += value - m_Captures; m_Captures = value; } } public int Score { get => m_Score; set { m_TeamInfo.Score += value - m_Score; m_Score = value; if (m_TeamInfo.Leader == null || m_Score > m_TeamInfo.Leader.Score) m_TeamInfo.Leader = this; } } } [PropertyObject] public sealed class CTFTeamInfo : IRankedCTF { public CTFTeamInfo(int teamID) { TeamID = teamID; Players = new Dictionary(); } public CTFTeamInfo(int teamID, GenericReader ip) { TeamID = teamID; Players = new Dictionary(); int version = ip.ReadEncodedInt(); switch (version) { case 2: { Board = ip.ReadItem() as CTFBoard; goto case 1; } case 1: { Name = ip.ReadString(); goto case 0; } case 0: { Color = ip.ReadEncodedInt(); Flag = ip.ReadItem() as CTFFlag; Origin = ip.ReadPoint3D(); break; } } } public CTFGame Game{ get; set; } public int TeamID{ get; } public CTFPlayerInfo Leader{ get; set; } [CommandProperty(AccessLevel.GameMaster)] public CTFBoard Board{ get; set; } public Dictionary Players{ get; } public CTFPlayerInfo this[Mobile mob] { get { if (mob == null) return null; if (!Players.TryGetValue(mob, out CTFPlayerInfo val)) Players[mob] = val = new CTFPlayerInfo(this, mob); return val; } } [CommandProperty(AccessLevel.GameMaster)] public int Color{ get; set; } [CommandProperty(AccessLevel.GameMaster)] public string Name{ get; set; } [CommandProperty(AccessLevel.GameMaster)] public CTFFlag Flag{ get; set; } [CommandProperty(AccessLevel.GameMaster)] public Point3D Origin{ get; set; } string IRankedCTF.Name => $"{Name} Team"; public int Kills{ get; set; } public int Captures{ get; set; } public int Score{ get; set; } public void Reset() { Kills = 0; Captures = 0; Score = 0; Leader = null; Players.Clear(); if (Flag != null) { Flag.m_TeamInfo = this; Flag.Hue = Color; Flag.SendHome(); } if (Board != null) Board.m_TeamInfo = this; } public void Serialize(GenericWriter op) { op.WriteEncodedInt(2); // version op.Write(Board); op.Write(Name); op.WriteEncodedInt(Color); op.Write(Flag); op.Write(Origin); } public override string ToString() => "..."; } public sealed class CTFController : EventController { [Constructible] public CTFController() { Visible = false; Movable = false; Duration = TimeSpan.FromMinutes(30.0); TeamInfo = new CTFTeamInfo[8]; for (int i = 0; i < TeamInfo.Length; ++i) TeamInfo[i] = new CTFTeamInfo(i); } public CTFController(Serial serial) : base(serial) { } public CTFTeamInfo[] TeamInfo{ get; private set; } [CommandProperty(AccessLevel.GameMaster)] public CTFTeamInfo Team1 => TeamInfo[0]; [CommandProperty(AccessLevel.GameMaster)] public CTFTeamInfo Team2 => TeamInfo[1]; [CommandProperty(AccessLevel.GameMaster)] public CTFTeamInfo Team3 => TeamInfo[2]; [CommandProperty(AccessLevel.GameMaster)] public CTFTeamInfo Team4 => TeamInfo[3]; [CommandProperty(AccessLevel.GameMaster)] public CTFTeamInfo Team5 => TeamInfo[4]; [CommandProperty(AccessLevel.GameMaster)] public CTFTeamInfo Team6 => TeamInfo[5]; [CommandProperty(AccessLevel.GameMaster)] public CTFTeamInfo Team7 => TeamInfo[6]; [CommandProperty(AccessLevel.GameMaster)] public CTFTeamInfo Team8 => TeamInfo[7]; [CommandProperty(AccessLevel.GameMaster)] public TimeSpan Duration{ get; set; } public override string Title => "CTF"; public override string GetTeamName(int teamID) => TeamInfo[teamID % TeamInfo.Length].Name; public override EventGame Construct(DuelContext context) => new CTFGame(this, context); public override void Serialize(GenericWriter writer) { base.Serialize(writer); writer.Write(2); writer.Write(Duration); writer.WriteEncodedInt(TeamInfo.Length); for (int i = 0; i < TeamInfo.Length; ++i) TeamInfo[i].Serialize(writer); } public override void Deserialize(GenericReader reader) { base.Deserialize(reader); int version = reader.ReadInt(); switch (version) { case 2: { Duration = reader.ReadTimeSpan(); goto case 1; } case 1: { TeamInfo = new CTFTeamInfo[reader.ReadEncodedInt()]; for (int i = 0; i < TeamInfo.Length; ++i) TeamInfo[i] = new CTFTeamInfo(i, reader); break; } case 0: { TeamInfo = new CTFTeamInfo[8]; for (int i = 0; i < TeamInfo.Length; ++i) TeamInfo[i] = new CTFTeamInfo(i); break; } } if (version < 2) Duration = TimeSpan.FromMinutes(30.0); } } public sealed class CTFGame : EventGame { private Timer m_FinishTimer; public CTFGame(CTFController controller, DuelContext context) : base(context) => Controller = controller; public CTFController Controller{ get; } public Map Facet { get { if (m_Context.Arena != null) return m_Context.Arena.Facet; return Controller.Map; } } public static void Initialize() { for (int i = 0x7C9; i <= 0x7D0; ++i) TileData.ItemTable[i].Flags |= TileFlag.NoShoot; } public void Alert(string text) { m_Context.m_Tournament?.Alert(text); for (int i = 0; i < m_Context.Participants.Count; ++i) { Participant p = m_Context.Participants[i]; for (int j = 0; j < p.Players.Length; ++j) if (p.Players[j] != null) p.Players[j].Mobile.SendMessage(0x35, text); } } public void Alert(string format, params object[] args) { Alert(string.Format(format, args)); } public CTFTeamInfo GetTeamInfo(Mobile mob) { int teamID = GetTeamID(mob); if (teamID >= 0) return Controller.TeamInfo[teamID % Controller.TeamInfo.Length]; return null; } public int GetTeamID(Mobile mob) { if (!(mob is PlayerMobile pm)) return -1; if (pm.DuelContext == null || pm.DuelContext != m_Context) return -1; if (pm.DuelPlayer?.Eliminated != false) return -1; return pm.DuelContext.Participants.IndexOf(pm.DuelPlayer.Participant); } public int GetColor(Mobile mob) { CTFTeamInfo teamInfo = GetTeamInfo(mob); if (teamInfo != null) return teamInfo.Color; return -1; } private void ApplyHues(Participant p, int hueOverride) { for (int i = 0; i < p.Players.Length; ++i) if (p.Players[i] != null) p.Players[i].Mobile.SolidHueOverride = hueOverride; } public void DelayBounce(TimeSpan ts, Mobile mob, Container corpse) { Timer.DelayCall(ts, () => DelayBounce_Callback(mob, corpse)); } private void DelayBounce_Callback(Mobile mob, Container corpse) { DuelPlayer dp = mob is PlayerMobile mobile ? mobile.DuelPlayer : null; m_Context.RemoveAggressions(mob); if (dp?.Eliminated == false) mob.MoveToWorld(m_Context.Arena.GetBaseStartPoint(GetTeamID(mob)), Facet); else m_Context.SendOutside(mob); m_Context.Refresh(mob, corpse); DuelContext.Debuff(mob); DuelContext.CancelSpell(mob); mob.Frozen = false; } public override bool OnDeath(Mobile mob, Container corpse) { Mobile killer = mob.FindMostRecentDamager(false); bool hadFlag = false; corpse.FindItemsByType(false).ForEach(flag => { hadFlag = true; flag.DropTo(mob, killer); }); mob.Backpack?.FindItemsByType(false).ForEach(flag => { hadFlag = true; flag.DropTo(mob, killer); }); if (killer?.Player == true) { CTFTeamInfo teamInfo = GetTeamInfo(killer); CTFTeamInfo victInfo = GetTeamInfo(mob); if (teamInfo != null && teamInfo != victInfo) { CTFPlayerInfo playerInfo = teamInfo[killer]; if (playerInfo != null) { playerInfo.Kills += 1; playerInfo.Score += 1; // base frag if (hadFlag) playerInfo.Score += 4; // fragged flag carrier if (mob.InRange(teamInfo.Origin, 24) && mob.Map == Facet) playerInfo.Score += 1; // fragged in base -- guarding for (int i = 0; i < Controller.TeamInfo.Length; ++i) { if (Controller.TeamInfo[i] == teamInfo) continue; Mobile ourFlagCarrier = null; if (Controller.TeamInfo[i].Flag != null) ourFlagCarrier = Controller.TeamInfo[i].Flag.RootParent as Mobile; if (ourFlagCarrier != null && GetTeamInfo(ourFlagCarrier) == teamInfo) { for (int j = 0; j < ourFlagCarrier.Aggressors.Count; ++j) { if (!(ourFlagCarrier.Aggressors[j] is AggressorInfo aggr) || aggr.Defender != ourFlagCarrier || aggr.Attacker != mob) continue; playerInfo.Score += 2; // helped defend guy capturing enemy flag break; } if (mob.Map == ourFlagCarrier.Map && ourFlagCarrier.InRange(mob, 12)) playerInfo.Score += 1; // helped defend guy capturing enemy flag } } } } } mob.CloseGump(); mob.SendGump(new CTFBoardGump(mob, this)); m_Context.Requip(mob, corpse); DelayBounce(TimeSpan.FromSeconds(30.0), mob, corpse); return false; } public override void OnStart() { for (int i = 0; i < Controller.TeamInfo.Length; ++i) { CTFTeamInfo teamInfo = Controller.TeamInfo[i]; teamInfo.Game = this; teamInfo.Reset(); } for (int i = 0; i < m_Context.Participants.Count; ++i) ApplyHues(m_Context.Participants[i], Controller.TeamInfo[i % 8].Color); m_FinishTimer?.Stop(); m_FinishTimer = Timer.DelayCall(Controller.Duration, Finish_Callback); } private void Finish_Callback() { List teams = new List(); for (int i = 0; i < m_Context.Participants.Count; ++i) { CTFTeamInfo teamInfo = Controller.TeamInfo[i % 8]; if (teamInfo?.Flag == null) continue; teams.Add(teamInfo); } teams.Sort(delegate(CTFTeamInfo a, CTFTeamInfo b) { return b.Score - a.Score; }); Tournament tourney = m_Context.m_Tournament; StringBuilder sb = new StringBuilder(); if (tourney != null) { if (tourney.TourneyType == TourneyType.FreeForAll) { sb.Append(m_Context.Participants.Count * tourney.PlayersPerParticipant); sb.Append("-man FFA"); } else if (tourney.TourneyType == TourneyType.RandomTeam) { sb.Append(tourney.ParticipantsPerMatch); sb.Append("-team"); } else if (tourney.TourneyType == TourneyType.RedVsBlue) { sb.Append("Red v Blue"); } else if (tourney.TourneyType == TourneyType.Faction) { sb.Append(tourney.ParticipantsPerMatch); sb.Append("-team Faction"); } else { for (int i = 0; i < tourney.ParticipantsPerMatch; ++i) { if (sb.Length > 0) sb.Append('v'); sb.Append(tourney.PlayersPerParticipant); } } } if (Controller != null) sb.Append(' ').Append(Controller.Title); string title = sb.ToString(); CTFTeamInfo winner = teams.Count > 0 ? teams[0] : null; for (int i = 0; i < teams.Count; ++i) { TrophyRank rank = TrophyRank.Bronze; if (i == 0) rank = TrophyRank.Gold; else if (i == 1) rank = TrophyRank.Silver; CTFPlayerInfo leader = teams[i].Leader; foreach (CTFPlayerInfo pl in teams[i].Players.Values) { Mobile mob = pl.Player; if (mob == null) continue; //"Red v Blue CTF Champion" sb = new StringBuilder(); sb.Append(title); if (pl == leader) sb.Append(" Leader"); if (pl.Score > 0) { sb.Append(": "); sb.Append(pl.Score.ToString("N0")); sb.Append(pl.Score == 1 ? " point" : " points"); if (pl.Kills > 0) { sb.Append(", "); sb.Append(pl.Kills.ToString("N0")); sb.Append(pl.Kills == 1 ? " kill" : " kills"); } if (pl.Captures > 0) { sb.Append(", "); sb.Append(pl.Captures.ToString("N0")); sb.Append(pl.Captures == 1 ? " capture" : " captures"); } } Item item = new Trophy(sb.ToString(), rank); if (pl == leader) item.ItemID = 4810; item.Name = $"{item.Name}, {teams[i].Name.ToLower()} team"; if (!mob.PlaceInBackpack(item)) mob.BankBox.DropItem(item); int cash = pl.Score * 250; if (cash > 0) { item = new BankCheck(cash); if (!mob.PlaceInBackpack(item)) mob.BankBox.DropItem(item); mob.SendMessage( "You have been awarded a {0} trophy and {1:N0}gp for your participation in this tournament.", rank.ToString().ToLower(), cash); } else { mob.SendMessage("You have been awarded a {0} trophy for your participation in this tournament.", rank.ToString().ToLower()); } } } for (int i = 0; i < m_Context.Participants.Count; ++i) { Participant p = m_Context.Participants[i]; for (int j = 0; j < p.Players.Length; ++j) { DuelPlayer dp = p.Players[j]; if (dp?.Mobile != null) { dp.Mobile.CloseGump(); dp.Mobile.SendGump(new CTFBoardGump(dp.Mobile, this)); } } if (i == winner.TeamID) continue; for (int j = 0; j < p.Players.Length; ++j) if (p.Players[j] != null) p.Players[j].Eliminated = true; } m_Context.Finish(m_Context.Participants[winner.TeamID]); } public override void OnStop() { for (int i = 0; i < Controller.TeamInfo.Length; ++i) { CTFTeamInfo teamInfo = Controller.TeamInfo[i]; if (teamInfo.Flag != null) { teamInfo.Flag.SendHome(); teamInfo.Flag.m_TeamInfo = null; } if (teamInfo.Board != null) teamInfo.Board.m_TeamInfo = null; teamInfo.Game = null; } for (int i = 0; i < m_Context.Participants.Count; ++i) ApplyHues(m_Context.Participants[i], -1); m_FinishTimer?.Stop(); m_FinishTimer = null; } } }