diff --git a/Scripts/Engines/ConPVP/Games/BombingRun.cs b/Scripts/Engines/ConPVP/Games/BombingRun.cs new file mode 100644 index 000000000..4683b18d5 --- /dev/null +++ b/Scripts/Engines/ConPVP/Games/BombingRun.cs @@ -0,0 +1,1959 @@ + +using System; +using System.Collections; +using System.Text; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; +using Server.Gumps; + +namespace Server.Engines.ConPVP +{ + public class BRBomb : Item + { + private BRGame m_Game; + private Mobile m_Thrower; + private EffectTimer m_Timer; + private bool m_Flying; + + private ArrayList m_Helpers; + + private Mobile FindOwner( object parent ) + { + if ( parent is Item ) + return ( (Item) parent ).RootParent as Mobile; + + if ( parent is Mobile ) + return (Mobile) parent; + + return null; + } + + public BRBomb( BRGame game ) : base( 0x103C ) // 0x103C = bread, 0x1042 = pie, 0x1364 = rock, 0x13a8 = pillow, 0x2256 = bagball + { + Name = "da bomb"; + Movable = false; + Hue = 0x35; + + m_Game = game; + + m_Helpers = new ArrayList(); + + m_Timer = new EffectTimer( this ); + m_Timer.Start(); + } + + private class EffectTimer : Timer + { + private BRBomb m_Bomb; + private int m_Count; + + public EffectTimer( BRBomb bomb ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 1.0 ) ) + { + m_Bomb = bomb; + m_Count = 0; + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if ( m_Bomb.Parent == null && m_Bomb.m_Game != null && m_Bomb.m_Game.Controller != null ) + { + if ( !m_Bomb.m_Flying && m_Bomb.Map != Map.Internal ) + Effects.SendLocationEffect( m_Bomb.GetWorldLocation(), m_Bomb.Map, 0x377A, 16, 10, m_Bomb.Hue, 0 ); + + if ( m_Bomb.Location != m_Bomb.m_Game.Controller.BombHome ) + { + if ( ++m_Count >= 30 ) + { + m_Bomb.m_Game.ReturnBomb(); + m_Bomb.m_Game.Alert( "The bomb has been returned to it's starting point." ); + + m_Count = 0; + m_Bomb.m_Helpers.Clear(); + } + } + else + { + m_Count = 0; + } + } + else + { + m_Count = 0; + } + } + } + + public BRBomb( Serial serial ) : base( serial ) + { + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize (reader); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + break; + } + } + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( Delete ) ).Start(); // delete this after the world loads + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize (writer); + + writer.Write( (int) 0 ); // version + } + + public override void OnAdded(IEntity parent) + { + base.OnAdded( parent ); + + Mobile mob = FindOwner( parent ); + + if ( mob != null ) + { + mob.SolidHueOverride = 0x0499; + + //int fighterRank = mob.Skills.Tactics.Value + mob.Skills.Anatomy + mob.Skills.Healing.Value + mob.Skills.Swords.Value + mob.Skills.Macing.Value + mob.Skills.Fencing.Value + mob.Skills.Archery.Value + mob.Skills.Parrying.Value; + //int mageRank = mob.Skills.Magery.Value + mob.Skills.Meditation.Value + mob.Skills.EvalInt.Value + mob.Skills.Inscribe.Value + mob.Skills.Wrestling.Value + mob.Skills.MagicResist; + //int theifRank = mob.Skills.Stealing.Value + mob.Skills.Snooping.Value + mob.Skills.Hiding.Value + mob.Skills.Stealth.Value + mob.Skills.RemoveTrap.Value + mob.Skills.Lockpicking.Value + mob.Skills.ItemID.Value; + + // To Do: Give them a special ability while holding the ball maybe based on skills? + } + } + + public override void OnRemoved(IEntity parent) + { + base.OnRemoved( parent ); + + Mobile mob = FindOwner( parent ); + + if ( mob != null && m_Game != null ) + mob.SolidHueOverride = m_Game.GetColor( mob ); + } + + public void DropTo( Mobile mob, Mobile killer ) + { + if ( mob != null && !mob.Deleted ) + this.MoveToWorld( mob.Location, mob.Map ); + else if ( killer != null && !killer.Deleted ) + this.MoveToWorld( killer.Location, killer.Map ); + else if ( m_Game != null ) + m_Game.ReturnBomb(); + } + + public override bool OnMoveOver( Mobile m ) + { + if ( m_Flying || !Visible || m_Game == null || m == null || !m.Alive ) + return true; + + BRTeamInfo useTeam = m_Game.GetTeamInfo( m ); + if ( useTeam == null ) + return true; + + return TakeBomb( m, useTeam, "picked up" ); + } + + public override void OnLocationChange(Point3D oldLocation) + { + base.OnLocationChange(oldLocation); + + if ( m_Flying || !Visible || m_Game == null || this.Parent != null ) + return; + + IPooledEnumerable eable = this.GetClientsInRange( 0 ); + foreach ( NetState ns in eable ) + { + Mobile m = ns.Mobile; + + if ( m == null || !m.Player || !m.Alive ) + continue; + + BRTeamInfo useTeam = m_Game.GetTeamInfo( m ); + if ( useTeam != null ) + TakeBomb( m, useTeam, "got" ); + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete (); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + public override void OnDoubleClick( Mobile m ) + { + if ( m_Game == null || !Visible || m == null || !m.Alive ) + return; + + if ( !m_Flying && IsChildOf( m.Backpack ) ) + { + m.Target = new BombTarget( this, m ); + } + else if ( this.Parent == null ) + { + if ( m.InRange( this.Location, 1 ) && m.Location.Z != this.Z ) + { + BRTeamInfo useTeam = m_Game.GetTeamInfo( m ); + if ( useTeam == null ) + return; + + TakeBomb( m, useTeam, "grabbed" ); + } + } + } + + private class BombTarget : Target + { + private BRBomb m_Bomb; + private Mobile m_Mob; + private bool m_Resend = true; + + public BombTarget( BRBomb bomb, Mobile from ) : base( 10, true, TargetFlags.None ) + { + CheckLOS = false; + + m_Bomb = bomb; + m_Mob = from; + + m_Mob.SendMessage( 0x26, "Where do you want to throw it?" ); + } + + protected override void OnTarget( Mobile from, object targeted ) + { + m_Resend = !m_Bomb.OnBombTarget( from, targeted ); + } + + protected override void OnTargetUntargetable( Mobile from, object targeted ) + { + m_Resend = !m_Bomb.OnBombTarget( from, targeted ); + } + + protected override void OnTargetFinish( Mobile from ) + { + base.OnTargetFinish( from ); + + // has to be delayed in case some other target canceled us... + if ( m_Resend ) + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( ResendBombTarget ) ).Start(); + } + + private void ResendBombTarget() + { + // Make sure they still have the bomb, then give them the target back + if ( m_Bomb != null && !m_Bomb.Deleted && m_Mob != null && !m_Mob.Deleted && m_Mob.Alive ) + { + if ( m_Bomb.IsChildOf( m_Mob ) ) + m_Mob.Target = new BombTarget( m_Bomb, m_Mob ); + } + } + } + + private bool OnBombTarget( Mobile from, object obj ) + { + if ( m_Game == null ) + return true; + + if ( !IsChildOf( from.Backpack ) ) + return true; + + // don't let them throw it to themselves + if ( obj == from ) + return false; + + if ( !(obj is IPoint3D) ) + return false; + + Point3D pt = new Point3D( (IPoint3D)obj ); + + if ( obj is Mobile ) + pt.Z += 10; + else if ( obj is Item ) + pt.Z += ((Item)obj).ItemData.CalcHeight + 1; + + m_Flying = true; + this.Visible = false; + m_Thrower = from; + this.MoveToWorld( this.GetWorldLocation(), from.Map ); + + BeginFlight( pt ); + return true; + } + + private void HitObject( Point3D ballLoc, int objZ, int objHeight ) + { + DoAnim( this.GetWorldLocation(), ballLoc, this.Map ); + this.MoveToWorld( ballLoc ); + + m_Path.Clear(); + m_PathIdx = 0; + + Timer.DelayCall( TimeSpan.FromSeconds( 0.05 ), new TimerCallback( ContinueFlight ) ).Start(); + } + + private bool CheckCatch( Mobile m, Point3D myLoc ) + { + if ( m == null || !m.Alive || !m.Player || m_Game == null ) + return false; + + if ( m_Game.GetTeamInfo( m ) == null ) + return false; + + int zdiff = myLoc.Z - m.Z; + + if ( zdiff < 0 ) + return false; + else if ( zdiff < 12 ) + return true; + else if ( zdiff < 16 ) + return Utility.RandomBool(); // 50% chance + else + return false; + } + + private void DoAnim( Point3D start, Point3D end, Map map ) + { + Effects.SendMovingEffect( new Entity( Serial.Zero, start, map ), new Entity( Serial.Zero, end, map ), + this.ItemID, 15, 0, false, false, this.Hue, 0 ); + } + + private void DoCatch( Mobile m ) + { + m_Flying = false; + this.Visible = true; + + if ( m == null || !m.Alive || !m.Player || m_Game == null ) + return; + + BRTeamInfo useTeam = m_Game.GetTeamInfo( m ); + + if ( useTeam == null ) + return; + + DoAnim( this.GetWorldLocation(), m.Location, m.Map ); + + string verb = "caught"; + + if ( m_Thrower != null && m_Game.GetTeamInfo( m_Thrower ) != useTeam ) + verb = "intercepted"; + + if ( !TakeBomb( m, useTeam, verb ) ) + this.MoveToWorld( m.Location, m.Map ); + } + + private Point3DList m_Path = new Point3DList(); + private int m_PathIdx = 0; + + private void BeginFlight( Point3D dest ) + { + Point3D org = this.GetWorldLocation(); + + org.Z += 10; // always add 10 at the start cause we're coming from a mobile's eye level + + /*if ( org.X > dest.X || ( org.X == dest.X && org.Y > dest.Y ) || ( org.X == dest.X && org.Y == dest.Y && org.Z > dest.Z ) ) + { + Point3D swap = org; + org = dest; + dest = swap; + }*/ + + ArrayList list = new ArrayList(); + double rise, run, zslp; + double dist3d, dist2d; + double x, y, z; + int xd, yd, zd; + Point3D p; + + xd = dest.X - org.X; + yd = dest.Y - org.Y; + zd = dest.Z - org.Z; + dist2d = Math.Sqrt( xd * xd + yd * yd ); + if ( zd != 0 ) + dist3d = Math.Sqrt( dist2d * dist2d + zd * zd ); + else + dist3d = dist2d; + + rise = ( (float) yd ) / dist3d; + run = ( (float) xd ) / dist3d; + zslp = ( (float) zd ) / dist3d; + + x = (int) org.X; + y = (int) org.Y; + z = (int) org.Z; + while ( Utility.NumberBetween( x, dest.X, org.X, 0.5 ) && Utility.NumberBetween( y, dest.Y, org.Y, 0.5 ) && Utility.NumberBetween( z, dest.Z, org.Z, 0.5 ) ) + { + int ix = (int) Math.Round( x ); + int iy = (int) Math.Round( y ); + int iz = (int) Math.Round( z ); + + if ( list.Count > 0 ) + { + p = (Point3D)list[list.Count-1]; + + if ( p.X != ix || p.Y != iy || p.Z != iz ) + list.Add( new Point3D( ix, iy, iz ) ); + } + else + { + list.Add( new Point3D( ix, iy, iz ) ); + } + + x += run; + y += rise; + z += zslp; + } + + if ( list.Count > 0 ) + { + if ( ((Point3D)list[list.Count-1]) != dest ) + list.Add( dest ); + } + + /*if ( dist3d > 4 && ( dest.X != org.X || dest.Y != org.Y ) ) + { + int count = list.Count; + int i; + int climb = count / 2; + if ( climb > 3 ) + climb = 3; + + for ( i = 0; i < climb; i++ ) + { + p = ((Point3D)list[i]); + p.Z += (i+1) * 4; + list[i] = p; + } + + for ( ; i < count - climb; i++ ) + { + p = ((Point3D)list[i]); + p.Z += 16; + list[i] = p; + } + + for ( i = climb; i > 0; i-- ) + { + p = ((Point3D)list[i]); + p.Z += i * 4; + list[i] = p; + } + }*/ + + if ( dist2d > 1 ) + { + int count = list.Count; + double height = count * 2 * ( Utility.RandomDouble() * 0.40 + 0.10 ); // 10 - 50% + double coeff = ( -height / ( (count*count)/4.0 ) ); + + for ( int i = 0; i < count; i++ ) + { + p = ((Point3D)list[i]); + + int xp = ( i - (count / 2) ); + + p.Z += (int)Math.Ceiling( coeff * xp * xp + height ); + + list[i] = p; + } + } + + m_Path.Clear(); + for (int i = 0; i < list.Count; i++) + m_Path.Add( (Point3D)list[i] ); + + m_PathIdx = 0; + + ContinueFlight(); + } + + private void ContinueFlight() + { + int height; + bool found = false; + + if ( m_PathIdx < m_Path.Count && this.Map != null && this.Map.Tiles != null && this.Map != Map.Internal ) + { + int pathCheckEnd = m_PathIdx + 5; + + if ( m_Path.Count < pathCheckEnd ) + pathCheckEnd = m_Path.Count; + + this.Visible = false; + + if ( m_PathIdx > 0 ) // move to the next location + this.MoveToWorld( m_Path[m_PathIdx - 1] ); + + Point3D pTop = new Point3D( this.GetWorldLocation() ), pBottom = new Point3D( m_Path[pathCheckEnd-1] ); + Utility.FixPoints( ref pTop, ref pBottom ); + + for ( int i = m_PathIdx; i < pathCheckEnd; i++ ) + { + Point3D point = m_Path[i]; + + LandTile landTile = this.Map.Tiles.GetLandTile( point.X, point.Y ); + int landZ = 0, landAvg = 0, landTop = 0; + this.Map.GetAverageZ( point.X, point.Y, ref landZ, ref landAvg, ref landTop ); + + if ( landZ <= point.Z && landTop >= point.Z && !landTile.Ignored ) + { + HitObject( point, landTop, 0 ); + return; + } + + StaticTile[] statics = this.Map.Tiles.GetStaticTiles( point.X, point.Y, true ); + + if ( landTile.ID == 0x244 && statics.Length == 0 ) // 0x244 = invalid land tile + { + bool empty = true; + IPooledEnumerable eable = this.Map.GetItemsInRange( point, 0 ); + + foreach ( Item item in eable ) + { + if ( item != this ) + { + empty = false; + break; + } + } + + eable.Free(); + + if ( empty ) + { + HitObject( point, landTop, 0 ); + return; + } + } + + for ( int j = 0; j < statics.Length; j++ ) + { + StaticTile t = statics[j]; + + ItemData id = TileData.ItemTable[t.ID & TileData.MaxItemValue]; + height = id.CalcHeight; + + if ( t.Z <= point.Z && t.Z + height >= point.Z && ( id.Flags & ( TileFlag.Impassable | TileFlag.Wall | TileFlag.NoShoot ) ) != 0 ) + { + if ( i > m_PathIdx ) + point = m_Path[i-1]; + else + point = this.GetWorldLocation(); + HitObject( point, t.Z, height ); + return; + } + } + } + + Rectangle2D rect = new Rectangle2D( pTop.X, pTop.Y, ( pBottom.X - pTop.X ) + 1, ( pBottom.Y - pTop.Y ) + 1 ); + + IPooledEnumerable area = this.Map.GetItemsInBounds( rect ); + foreach ( Item i in area ) + { + if ( i == this || i.ItemID >= 0x4000 ) + continue; + + if ( i is BRGoal ) + { + height = 17; + } + else if ( i is Blocker ) + { + height = 20; + } + else + { + ItemData id = i.ItemData; + if ( ( id.Flags & (TileFlag.Impassable | TileFlag.Wall | TileFlag.NoShoot)) == 0 ) + continue; + height = id.CalcHeight; + } + + Point3D point = i.Location; + Point3D loc = i.Location; + for ( int j = m_PathIdx; j < pathCheckEnd; j++ ) + { + point = m_Path[j]; + + if ( loc.X == point.X && loc.Y == point.Y && + ( (i is Blocker ) || ( loc.Z <= point.Z && loc.Z + height >= point.Z ) ) ) + { + found = true; + if ( j > m_PathIdx ) + point = m_Path[j-1]; + else + point = this.GetWorldLocation(); + break; + } + } + + if ( !found ) + continue; + + area.Free(); + if ( i is BRGoal ) + { + Point3D oldLoc = new Point3D( this.GetWorldLocation() ); + if ( CheckScore( (BRGoal)i, m_Thrower, 3 ) ) + DoAnim( oldLoc, point, this.Map ); + else + HitObject( point, loc.Z, height ); + } + else + { + HitObject( point, loc.Z, height ); + } + return; + } + + area.Free(); + + area = this.Map.GetClientsInBounds( rect ); + foreach ( NetState ns in area ) + { + Mobile m = ns.Mobile; + + if ( m == null || m == m_Thrower ) + continue; + + Point3D point; + Point3D loc = m.Location; + + for ( int j = m_PathIdx; j < pathCheckEnd && !found; j++ ) + { + point = m_Path[j]; + + if ( loc.X == point.X && loc.Y == point.Y && + loc.Z <= point.Z && loc.Z + 16 >= point.Z ) + { + found = CheckCatch( m, point ); + } + } + + if ( !found ) + continue; + + area.Free(); + + // TODO: probably need to change this a lot... + DoCatch( m ); + + return; + } + + area.Free(); + + m_PathIdx = pathCheckEnd; + + if ( m_PathIdx > 0 && m_PathIdx - 1 < m_Path.Count ) + DoAnim( this.GetWorldLocation(), m_Path[m_PathIdx - 1], this.Map ); + + Timer.DelayCall( TimeSpan.FromSeconds( 0.1 ), new TimerCallback( ContinueFlight ) ).Start(); + } + else + { + if ( m_PathIdx > 0 && m_PathIdx - 1 < m_Path.Count ) + this.MoveToWorld( m_Path[m_PathIdx - 1] ); + else if ( m_Path.Count > 0 ) + this.MoveToWorld( m_Path.Last ); + + int myZ = this.Map.GetAverageZ( this.X, this.Y ); + + StaticTile[] statics = this.Map.Tiles.GetStaticTiles( this.X, this.Y, true ); + for ( int j = 0; j < statics.Length; j++ ) + { + StaticTile t = statics[j]; + + ItemData id = TileData.ItemTable[t.ID & TileData.MaxItemValue]; + height = id.CalcHeight; + + if ( t.Z + height > myZ && t.Z + height <= this.Z ) + myZ = t.Z + height; + } + + IPooledEnumerable eable = this.GetItemsInRange( 0 ); + foreach ( Item item in eable ) + { + if ( item.Visible && item != this ) + { + height = item.ItemData.CalcHeight; + if ( item.Z + height > myZ && item.Z + height <= this.Z ) + myZ = item.Z + height; + } + } + eable.Free(); + + this.Z = myZ; + m_Flying = false; + this.Visible = true; + + m_Path.Clear(); + m_PathIdx = 0; + } + } + + public Mobile Thrower { get { return m_Thrower; } } + + public bool CheckScore( BRGoal goal, Mobile m, int points ) + { + if ( m_Game == null || m == null || goal == null ) + return false; + + BRTeamInfo team = m_Game.GetTeamInfo( m ); + if ( team == null || goal.Team == null || team == goal.Team ) + return false; + + if ( points > 3 ) + m_Game.Alert( "Touchdown {0} ({1})!", team.Name, m.Name ); + else + m_Game.Alert( "Field goal {0} ({1})!", team.Name, m.Name ); + + for (int i = m_Helpers.Count - 1; i >= 0; i--) + { + Mobile mob = (Mobile)m_Helpers[i]; + + BRPlayerInfo pi = team[mob]; + if ( pi != null ) + { + if ( mob == m ) + pi.Captures += points; + + pi.Score += points + 1; + + points /= 2; + } + } + + m_Game.ReturnBomb(); + + m_Flying = false; + this.Visible = true; + m_Path.Clear(); + m_PathIdx = 0; + + Target.Cancel( m ); + + return true; + } + + private bool TakeBomb( Mobile m, BRTeamInfo team, string verb ) + { + if ( !m.Player || !m.Alive || m.NetState == null ) + return false; + + if ( m.PlaceInBackpack( this ) ) + { + m.RevealingAction(); + + m.LocalOverheadMessage( MessageType.Regular, 0x59, false, "You got the bomb!" ); + m_Game.Alert( "{1} ({2}) {0} the bomb!", verb, m.Name, team.Name ); + + m.Target = new BombTarget( this, m ); + + if ( m_Helpers.Contains( m ) ) + m_Helpers.Remove( m ); + + if ( m_Helpers.Count > 0 ) + { + Mobile last = (Mobile)m_Helpers[0]; + + if ( m_Game.GetTeamInfo( last ) != team ) + m_Helpers.Clear(); + } + + m_Helpers.Add( m ); + + return true; + } + else + { + return false; + } + } + } + + public class BRGoal : BaseAddon + { + private bool m_North = false; + + [CommandProperty( AccessLevel.GameMaster )] + public bool North { get { return m_North; } set { m_North = value; Remake(); } } + + private static AddonComponent SetHue( AddonComponent ac, int hue ) + { + ac.Hue = hue; + return ac; + } + + private void Remake() + { + foreach ( AddonComponent ac in this.Components ) + { + ac.Addon = null; + ac.Delete(); + } + + this.Components.Clear(); + + // stairs + this.AddComponent( new AddonComponent( 0x74D ), -1, +1, -5 ); + this.AddComponent( new AddonComponent( 0x71F ), 0, +1, -5 ); + this.AddComponent( new AddonComponent( 0x74B ), +1, +1, -5 ); + this.AddComponent( new AddonComponent( 0x736 ), +1, 0, -5 ); + this.AddComponent( new AddonComponent( 0x74C ), +1, -1, -5 ); + this.AddComponent( new AddonComponent( 0x737 ), 0, -1, -5 ); + this.AddComponent( new AddonComponent( 0x74A ), -1, -1, -5 ); + this.AddComponent( new AddonComponent( 0x749 ), -1, 0, -5 ); + + // Center Sparkle + this.AddComponent( new AddonComponent( 0x375A ), 0, 0, -1 ); + + if ( !m_North ) + { + // Pillars + this.AddComponent( new AddonComponent( 0x0CE ), 0, +1, -2 ); + this.AddComponent( new AddonComponent( 0x0CC ), 0, -1, -2 ); + this.AddComponent( new AddonComponent( 0x0D0 ), 0, 0, -2 ); + + // Yellow parts + this.AddComponent( SetHue( new AddonComponent( 0x0DF ), 0x499 ), 0, +1, 7 ); + this.AddComponent( SetHue( new AddonComponent( 0x0DF ), 0x499 ), 0, 0, 16 ); + this.AddComponent( SetHue( new AddonComponent( 0x0DF ), 0x499 ), 0, -1, 7 ); + + // Blue Sparkles + this.AddComponent( SetHue( new AddonComponent( 0x377A ), 0x84C ), 0, +1, 12 ); + this.AddComponent( SetHue( new AddonComponent( 0x377A ), 0x84C ), 0, +1, -1 ); + this.AddComponent( SetHue( new AddonComponent( 0x377A ), 0x84C ), 0, -1, 12 ); + this.AddComponent( SetHue( new AddonComponent( 0x377A ), 0x84C ), 0, -1, -1 ); + } + else + { + // Pillars + this.AddComponent( new AddonComponent( 0x0CF ), +1, 0, -2 ); + this.AddComponent( new AddonComponent( 0x0CC ), -1, 0, -2 ); + this.AddComponent( new AddonComponent( 0x0D1 ), 0, 0, -2 ); + + // Yellow parts + this.AddComponent( SetHue( new AddonComponent( 0x0DF ), 0x499 ), +1, 0, 7 ); + this.AddComponent( SetHue( new AddonComponent( 0x0DF ), 0x499 ), 0, 0, 16 ); + this.AddComponent( SetHue( new AddonComponent( 0x0DF ), 0x499 ), -1, 0, 7 ); + + // Blue Sparkles + this.AddComponent( SetHue( new AddonComponent( 0x377A ), 0x84C ), +1, 0, 12 ); + this.AddComponent( SetHue( new AddonComponent( 0x377A ), 0x84C ), +1, 0, -1 ); + this.AddComponent( SetHue( new AddonComponent( 0x377A ), 0x84C ), -1, 0, 12 ); + this.AddComponent( SetHue( new AddonComponent( 0x377A ), 0x84C ), -1, 0, -1 ); + } + } + + [Constructable] + public BRGoal() + { + Name = "Bombing Run Goal"; + + this.ItemID = 0x51D; + this.Hue = 0x84C; + this.Visible = true; + + Remake(); + } + + public BRGoal( Serial serial ) : base( serial ) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize (writer); + + writer.Write( (int)1 ); // version + + writer.Write( m_North ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize (reader); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_North = reader.ReadBool(); + goto case 0; + } + case 0: + { + break; + } + } + + this.Hue = 0x84C; + } + + public override bool ShareHue{ get{ return false; } } + + public BRTeamInfo Team + { + get { return m_Team; } + set + { + m_Team = value; + if ( m_Team != null && m_Team.Color != 0 ) + this.Hue = m_Team.Color; + else + this.Hue = 0x84C; + } + } + + private BRTeamInfo m_Team; + + public override bool OnMoveOver( Mobile m ) + { + if ( !Visible ) + return true; + + if ( m == null || !m.Player || !m.Alive || m.Backpack == null || m_Team == null || m_Team.Game == null ) + return true; + + if ( !base.OnMoveOver( m ) ) + return false; + + if ( m_Team != null && m_Team.Color != 0 ) + this.Hue = m_Team.Color; + else + this.Hue = 0x84C; + + BRBomb b = m.Backpack.FindItemByType( typeof( BRBomb ), true ) as BRBomb; + + if ( b != null ) + b.CheckScore( this, m, 7 ); + + return true; + } + } + + public sealed class BRBoard : Item + { + public BRTeamInfo m_TeamInfo; + + [Constructable] + public BRBoard() + : base( 7774 ) + { + Name = "Scoreboard"; + Movable = false; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_TeamInfo != null && m_TeamInfo.Game != null ) + { + from.CloseGump( typeof( BRBoardGump ) ); + from.SendGump( new BRBoardGump( from, m_TeamInfo.Game ) ); + } + } + + public BRBoard( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BRBoardGump : Gump + { + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", 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, false, false ); + else + AddHtml( x, y, width, height, Color( text, color ), false, false ); + } + + private const int LabelColor32 = 0xFFFFFF; + private const int BlackColor32 = 0x000000; + + private BRGame m_Game; + + public BRBoardGump( Mobile mob, BRGame game ) + : this( mob, game, null ) + { + } + + public BRBoardGump( Mobile mob, BRGame game, BRTeamInfo section ) + : base( 60, 60 ) + { + m_Game = game; + + BRTeamInfo ourTeam = game.GetTeamInfo( mob ); + + ArrayList entries = new ArrayList(); + + if ( section == null ) + { + for ( int i = 0; i < game.Context.Participants.Count; ++i ) + { + BRTeamInfo teamInfo = game.Controller.TeamInfo[i % game.Controller.TeamInfo.Length]; + + if ( teamInfo == null ) + continue; + + entries.Add( teamInfo ); + } + } + else + { + foreach ( BRPlayerInfo 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( "BR 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 ) + { + BRTeamInfo teamInfo = entries[i] as BRTeamInfo; + + 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, String.Format( "{0}: {1}", LadderGump.Rank( 1 + i ), teamInfo.Name ), 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, "Points:", 0xFFC000, BlackColor32 ); + AddBorderedText( 160 + 15, 105 + ( i * 75 ), 100, 20, teamInfo.Captures.ToString( "N0" ), 0xFFC000, BlackColor32 ); + + BRPlayerInfo 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 ); + } + } + else + { + } + + AddButton( 314, height - 42, 247, 248, 1, GumpButtonType.Reply, 0 ); + } + } + + public sealed class BRPlayerInfo : IRankedCTF, IComparable + { + private BRTeamInfo m_TeamInfo; + + private Mobile m_Player; + + private int m_Kills; + private int m_Captures; + + private int m_Score; + + public Mobile Player { get { return m_Player; } } + + public int CompareTo( object obj ) + { + BRPlayerInfo pi = (BRPlayerInfo)obj; + int res = pi.Captures.CompareTo( this.Captures ); + if ( res == 0 ) + { + res = pi.Score.CompareTo( this.Score ); + + if ( res == 0 ) + res = pi.Kills.CompareTo( this.Kills ); + } + return res; + } + + public string Name + { + get { return m_Player.Name; } + } + + public int Kills + { + get + { + return m_Kills; + } + set + { + m_TeamInfo.Kills += ( value - m_Kills ); + m_Kills = value; + } + } + + public int Captures + { + get + { + return m_Captures; + } + set + { + m_TeamInfo.Captures += ( value - m_Captures ); + m_Captures = value; + } + } + + public int Score + { + get + { + return 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; + } + } + + public BRPlayerInfo( BRTeamInfo teamInfo, Mobile player ) + { + m_TeamInfo = teamInfo; + m_Player = player; + } + } + + [PropertyObject] + public sealed class BRTeamInfo : IRankedCTF, IComparable + { + private BRGame m_Game; + private int m_TeamID; + + private int m_Color; + private string m_Name; + + private BRBoard m_Board; + private BRGoal m_Goal; + + private int m_Kills; + private int m_Captures; + + private int m_Score; + + private Hashtable m_Players; + + public int CompareTo( object obj ) + { + BRTeamInfo ti = (BRTeamInfo)obj; + int res = ti.Captures.CompareTo( this.Captures ); + if ( res == 0 ) + { + res = ti.Score.CompareTo( this.Score ); + + if ( res == 0 ) + res = ti.Kills.CompareTo( this.Kills ); + } + return res; + } + + public string Name + { + get { return String.Format( "{0} Team", m_Name ); } + } + + public BRGame Game { get { return m_Game; } set { m_Game = value; } } + public int TeamID { get { return m_TeamID; } } + + public int Kills { get { return m_Kills; } set { m_Kills = value; } } + public int Captures { get { return m_Captures; } set { m_Captures = value; } } + + public int Score { get { return m_Score; } set { m_Score = value; } } + + private BRPlayerInfo m_Leader; + + public BRPlayerInfo Leader + { + get { return m_Leader; } + set { m_Leader = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public BRBoard Board + { + get { return m_Board; } + set { m_Board = value; } + } + + public Hashtable Players + { + get { return m_Players; } + } + + public BRPlayerInfo this[Mobile mob] + { + get + { + if ( mob == null ) + return null; + + BRPlayerInfo val = m_Players[mob] as BRPlayerInfo; + + if ( val == null ) + m_Players[mob] = val = new BRPlayerInfo( this, mob ); + + return val; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Color + { + get { return m_Color; } + set { m_Color = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string TeamName + { + get { return m_Name; } + set { m_Name = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public BRGoal Goal + { + get { return m_Goal; } + set + { + m_Goal = value; + if ( m_Goal != null ) + m_Goal.Team = this; + } + } + + public BRTeamInfo( int teamID ) + { + m_TeamID = teamID; + m_Players = new Hashtable(); + } + + public void Reset() + { + m_Kills = 0; + m_Captures = 0; + m_Score = 0; + + m_Leader = null; + + m_Players.Clear(); + + if ( m_Board != null ) + m_Board.m_TeamInfo = this; + if ( m_Goal != null ) + m_Goal.Team = this; + } + + public BRTeamInfo( int teamID, GenericReader ip ) + { + m_TeamID = teamID; + m_Players = new Hashtable(); + + int version = ip.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + m_Board = ip.ReadItem() as BRBoard; + m_Name = ip.ReadString(); + m_Color = ip.ReadEncodedInt(); + m_Goal = ip.ReadItem() as BRGoal; + break; + } + } + } + + public void Serialize( GenericWriter op ) + { + op.WriteEncodedInt( 0 ); // version + + op.Write( m_Board ); + + op.Write( m_Name ); + + op.WriteEncodedInt( m_Color ); + + op.Write( m_Goal ); + } + + public override string ToString() + { + if ( m_Name != null ) + return String.Format( "({0}) ...", this.Name ); + else + return "..."; + } + } + + public sealed class BRController : EventController + { + private BRTeamInfo[] m_TeamInfo; + private TimeSpan m_Duration; + private Point3D m_BombHome; + + public BRTeamInfo[] TeamInfo { get { return m_TeamInfo; } } + + [CommandProperty( AccessLevel.GameMaster )] + public BRTeamInfo Team1 { get { return m_TeamInfo[0]; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public BRTeamInfo Team2 { get { return m_TeamInfo[1]; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public BRTeamInfo Team3 { get { return m_TeamInfo[2]; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public BRTeamInfo Team4 { get { return m_TeamInfo[3]; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan Duration + { + get { return m_Duration; } + set { m_Duration = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D BombHome + { + get { return m_BombHome; } + set { m_BombHome = value; } + } + + public override string Title + { + get { return "Bombing Run"; } + } + + public override string GetTeamName( int teamID ) + { + return m_TeamInfo[teamID % m_TeamInfo.Length].Name; + } + + public override EventGame Construct( DuelContext context ) + { + return new BRGame( this, context ); + } + + [Constructable] + public BRController() + { + Visible = false; + Movable = false; + + Name = "Bombing Run Controller"; + + m_Duration = TimeSpan.FromMinutes( 30.0 ); + + m_BombHome = Point3D.Zero; + + m_TeamInfo = new BRTeamInfo[4]; + + for ( int i = 0; i < m_TeamInfo.Length; ++i ) + m_TeamInfo[i] = new BRTeamInfo( i ); + } + + public BRController( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( m_BombHome ); + + writer.Write( m_Duration ); + + writer.WriteEncodedInt( m_TeamInfo.Length ); + + for ( int i = 0; i < m_TeamInfo.Length; ++i ) + m_TeamInfo[i].Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_BombHome = reader.ReadPoint3D(); + + m_Duration = reader.ReadTimeSpan(); + + m_TeamInfo = new BRTeamInfo[reader.ReadEncodedInt()]; + + for ( int i = 0; i < m_TeamInfo.Length; ++i ) + m_TeamInfo[i] = new BRTeamInfo( i, reader ); + + break; + } + } + } + } + + public sealed class BRGame : EventGame + { + public override bool CantDoAnything( Mobile mob ) + { + if ( mob == null || mob.Backpack == null || GetTeamInfo( mob ) == null ) + return false; + + Item bomb = mob.Backpack.FindItemByType( typeof( BRBomb ), true ); + + if ( bomb != null ) + return true; + + return false; + } + + private BRBomb m_Bomb; + + private TimerCallback m_UnhideCallback = null; + + public void ReturnBomb() + { + if ( m_Bomb != null && m_Controller != null ) + { + if ( m_UnhideCallback == null ) + m_UnhideCallback = new TimerCallback( UnhideBomb ); + m_Bomb.Visible = false; + m_Bomb.MoveToWorld( m_Controller.BombHome, m_Controller.Map ); + Timer.DelayCall( TimeSpan.FromSeconds( Utility.RandomMinMax( 5, 15 ) ), m_UnhideCallback ); + } + } + + private void UnhideBomb() + { + if ( m_Bomb != null ) + { + m_Bomb.Visible = true; + m_Bomb.OnLocationChange( m_Bomb.Location ); + } + } + + private BRController m_Controller; + + public BRController Controller { get { return m_Controller; } } + + public void Alert( string text ) + { + if ( m_Context.m_Tournament != null ) + m_Context.m_Tournament.Alert( text ); + + for ( int i = 0; i < m_Context.Participants.Count; ++i ) + { + Participant p = m_Context.Participants[i] as Participant; + + 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 BRGame( BRController controller, DuelContext context ) : base( context ) + { + m_Controller = controller; + } + + public Map Facet + { + get + { + if ( m_Context.Arena != null ) + return m_Context.Arena.Facet; + + return m_Controller.Map; + } + } + + public BRTeamInfo GetTeamInfo( Mobile mob ) + { + int teamID = GetTeamID( mob ); + + if ( teamID >= 0 ) + return m_Controller.TeamInfo[teamID % m_Controller.TeamInfo.Length]; + + return null; + } + + public int GetTeamID( Mobile mob ) + { + PlayerMobile pm = mob as PlayerMobile; + + if ( pm == null ) + { + if ( mob is BaseCreature ) + return ((BaseCreature)mob).Team - 1; + else + return -1; + } + + if ( pm.DuelContext == null || pm.DuelContext != m_Context ) + return -1; + + if ( pm.DuelPlayer == null || pm.DuelPlayer.Eliminated ) + return -1; + + return pm.DuelContext.Participants.IndexOf( pm.DuelPlayer.Participant ); + } + + public int GetColor( Mobile mob ) + { + BRTeamInfo 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, new TimerStateCallback( DelayBounce_Callback ), new object[] { mob, corpse } ); + } + + private void DelayBounce_Callback( object state ) + { + object[] states = (object[]) state; + Mobile mob = (Mobile) states[0]; + Container corpse = (Container) states[1]; + + DuelPlayer dp = null; + + if ( mob is PlayerMobile ) + dp = ( mob as PlayerMobile ).DuelPlayer; + + m_Context.RemoveAggressions( mob ); + + if ( dp != null && !dp.Eliminated ) + 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 hadBomb = false; + + Item[] bombs = corpse.FindItemsByType( typeof( BRBomb ), false ); + + for ( int i = 0; i < bombs.Length; ++i ) + ( bombs[i] as BRBomb ).DropTo( mob, killer ); + + hadBomb = ( hadBomb || bombs.Length > 0 ); + + if ( mob.Backpack != null ) + { + bombs = mob.Backpack.FindItemsByType( typeof( BRBomb ), false ); + + for ( int i = 0; i < bombs.Length; ++i ) + ( bombs[i] as BRBomb ).DropTo( mob, killer ); + + hadBomb = ( hadBomb || bombs.Length > 0 ); + } + + if ( killer != null && killer.Player ) + { + BRTeamInfo teamInfo = GetTeamInfo( killer ); + BRTeamInfo victInfo = GetTeamInfo( mob ); + + if ( teamInfo != null && teamInfo != victInfo ) + { + BRPlayerInfo playerInfo = teamInfo[killer]; + + if ( playerInfo != null ) + { + playerInfo.Kills += 1; + playerInfo.Score += 1; // base frag + + if ( hadBomb ) + playerInfo.Score += 4; // fragged bomb carrier + } + } + } + + mob.CloseGump( typeof( BRBoardGump ) ); + mob.SendGump( new BRBoardGump( mob, this ) ); + + m_Context.Requip( mob, corpse ); + DelayBounce( TimeSpan.FromSeconds( 30.0 ), mob, corpse ); + + return false; + } + + private Timer m_FinishTimer; + + public override void OnStart() + { + for ( int i = 0; i < m_Controller.TeamInfo.Length; ++i ) + { + BRTeamInfo teamInfo = m_Controller.TeamInfo[i]; + + teamInfo.Game = this; + teamInfo.Reset(); + } + + for ( int i = 0; i < m_Context.Participants.Count; ++i ) + ApplyHues( m_Context.Participants[i] as Participant, m_Controller.TeamInfo[i % m_Controller.TeamInfo.Length].Color ); + + if ( m_FinishTimer != null ) + m_FinishTimer.Stop(); + + m_Bomb = new BRBomb( this ); + ReturnBomb(); + + m_FinishTimer = Timer.DelayCall( m_Controller.Duration, new TimerCallback( Finish_Callback ) ); + } + + private void Finish_Callback() + { + ArrayList teams = new ArrayList(); + + for ( int i = 0; i < m_Context.Participants.Count; ++i ) + { + BRTeamInfo teamInfo = m_Controller.TeamInfo[i % m_Controller.TeamInfo.Length]; + + if ( teamInfo == null ) + continue; + + teams.Add( teamInfo ); + } + + teams.Sort(); + + Tournament tourny = m_Context.m_Tournament; + + StringBuilder sb = new StringBuilder(); + + if ( tourny != null && tourny.TournyType == TournyType.FreeForAll ) + { + sb.Append( m_Context.Participants.Count * tourny.PlayersPerParticipant ); + sb.Append( "-man FFA" ); + } + else if ( tourny != null && tourny.TournyType == TournyType.RandomTeam ) + { + sb.Append( tourny.ParticipantsPerMatch ); + sb.Append( "-team" ); + } + else if ( tourny != null && tourny.TournyType == TournyType.RedVsBlue ) + { + sb.Append( "Red v Blue" ); + } + else if ( tourny != null && tourny.TournyType == TournyType.Faction ) + { + sb.Append( tourny.ParticipantsPerMatch ); + sb.Append( "-team Faction" ); + } + else if ( tourny != null ) + { + for ( int i = 0; i < tourny.ParticipantsPerMatch; ++i ) + { + if ( sb.Length > 0 ) + sb.Append( 'v' ); + + sb.Append( tourny.PlayersPerParticipant ); + } + } + + if ( m_Controller != null ) + sb.Append( ' ' ).Append( m_Controller.Title ); + + string title = sb.ToString(); + + BRTeamInfo winner = (BRTeamInfo)( 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; + + BRPlayerInfo leader = ((BRTeamInfo)teams[i]).Leader; + + foreach ( BRPlayerInfo pl in ((BRTeamInfo)teams[i]).Players.Values ) + { + Mobile mob = pl.Player; + + if ( mob == null ) + continue; + + 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" ); + + 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 ? " point" : " points" ); + } + } + + Item item = new Trophy( sb.ToString(), rank ); + + if ( pl == leader ) + item.ItemID = 4810; + + item.Name = String.Format( "{0}, {1} team", item.Name, ((BRTeamInfo)teams[i]).Name.ToLower() ); + + 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] as Participant; + + if ( p == null || p.Players == null ) + continue; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer dp = p.Players[j]; + + if ( dp != null && dp.Mobile != null ) + { + dp.Mobile.CloseGump( typeof( BRBoardGump ) ); + dp.Mobile.SendGump( new BRBoardGump( dp.Mobile, this ) ); + } + } + + if ( i == winner.TeamID ) + continue; + + if ( p != null && p.Players != null ) + { + 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] as Participant ); + } + + public override void OnStop() + { + for ( int i = 0; i < m_Controller.TeamInfo.Length; ++i ) + { + BRTeamInfo teamInfo = m_Controller.TeamInfo[i]; + + if ( teamInfo.Board != null ) + teamInfo.Board.m_TeamInfo = null; + + teamInfo.Game = null; + } + + ReturnBomb(); + + if( m_Bomb != null ) + m_Bomb.Delete(); + + for ( int i = 0; i < m_Context.Participants.Count; ++i ) + ApplyHues( m_Context.Participants[i] as Participant, -1 ); + + if ( m_FinishTimer != null ) + m_FinishTimer.Stop(); + + m_FinishTimer = null; + } + } +} diff --git a/Scripts/Engines/ConPVP/Games/CTF.cs b/Scripts/Engines/ConPVP/Games/CTF.cs new file mode 100644 index 000000000..5e22ae4f3 --- /dev/null +++ b/Scripts/Engines/ConPVP/Games/CTF.cs @@ -0,0 +1,1332 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; +using Server.Gumps; + +namespace Server.Engines.ConPVP +{ + public sealed class CTFBoard : Item + { + public CTFTeamInfo m_TeamInfo; + + public override string DefaultName + { + get { return "scoreboard"; } + } + + [Constructable] + public CTFBoard() + : base( 7774 ) + { + Movable = false; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_TeamInfo != null && m_TeamInfo.Game != null ) + { + from.CloseGump( typeof( CTFBoardGump ) ); + from.SendGump( new CTFBoardGump( from, m_TeamInfo.Game ) ); + } + } + + public CTFBoard( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CTFBoardGump : Gump + { + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", 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, false, false ); + else + AddHtml( x, y, width, height, Color( text, color ), false, false ); + } + + private const int LabelColor32 = 0xFFFFFF; + private const int BlackColor32 = 0x000000; + + private CTFGame m_Game; + + public CTFBoardGump( Mobile mob, CTFGame game ) + : this( mob, game, null ) + { + } + + public CTFBoardGump( Mobile mob, CTFGame game, CTFTeamInfo section ) + : 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 == null || 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, String.Format( "{0}: {1} Team", LadderGump.Rank( 1 + i ), teamInfo.Name ), 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 ); + } + } + else + { + } + + AddButton( 314, height - 42, 247, 248, 1, GumpButtonType.Reply, 0 ); + } + } + + public sealed class CTFFlag : Item + { + public CTFTeamInfo m_TeamInfo; + + public override string DefaultName + { + get { return "old people cookies"; } + } + + public Mobile m_Fragger; + public DateTime m_FragTime; + + public Mobile m_Returner; + public DateTime m_ReturnTime; + + private int m_ReturnCount; + private Timer m_ReturnTimer; + + [Constructable] + public CTFFlag() + : base( 5643 ) + { + Movable = false; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_TeamInfo != null && 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, new TargetCallback( 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 ( this.Location == m_TeamInfo.Origin && this.Map == m_TeamInfo.Game.Facet ) + { + from.Send( new UnicodeMessage( this.Serial, this.ItemID, MessageType.Regular, 0x3B2, 3, "ENU", this.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() + { + if ( m_ReturnTimer != null ) + m_ReturnTimer.Stop(); + + m_ReturnTimer = null; + } + + private void BeginCountdown( int returnCount ) + { + StopCountdown(); + + m_ReturnTimer = Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ), new TimerCallback( Countdown_OnTick ) ); + m_ReturnCount = returnCount; + } + + private void Countdown_OnTick() + { + Mobile owner = this.RootParent as Mobile; + + switch ( m_ReturnCount ) + { + case 60: + case 30: + case 15: + case 10: + case 5: + case 4: + case 3: + case 2: + case 1: + { + if ( owner != null ) + 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(); + + if ( m_TeamInfo != null && m_TeamInfo.Game != null ) + 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 ) + { + Mobile passTo = obj as Mobile; + + 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, String.Format( "{0} has passed you the cookies!", from.Name ) ); + } + 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( object parent ) + { + if ( parent is Item ) + return ( (Item) parent ).RootParent as Mobile; + + if ( parent is Mobile ) + return (Mobile) parent; + + 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 == null ? -1 : m_TeamInfo.Game.GetColor( mob ) ); + } + + public CTFFlag( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 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 CTFTeamInfo m_TeamInfo; + + private Mobile m_Player; + + private int m_Kills; + private int m_Captures; + + private int m_Score; + + public Mobile Player { get { return m_Player; } } + + string IRankedCTF.Name + { + get { return m_Player.Name; } + } + + public int Kills + { + get + { + return m_Kills; + } + set + { + m_TeamInfo.Kills += ( value - m_Kills ); + m_Kills = value; + } + } + + public int Captures + { + get + { + return m_Captures; + } + set + { + m_TeamInfo.Captures += ( value - m_Captures ); + m_Captures = value; + } + } + + public int Score + { + get + { + return 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; + } + } + + public CTFPlayerInfo( CTFTeamInfo teamInfo, Mobile player ) + { + m_TeamInfo = teamInfo; + m_Player = player; + } + } + + [PropertyObject] + public sealed class CTFTeamInfo : IRankedCTF + { + private CTFGame m_Game; + private int m_TeamID; + + private int m_Color; + private string m_Name; + + private CTFBoard m_Board; + + private CTFFlag m_Flag; + private Point3D m_Origin; + + private int m_Kills; + private int m_Captures; + + private int m_Score; + + private Dictionary m_Players; + + string IRankedCTF.Name + { + get { return String.Format( "{0} Team", m_Name ); } + } + + public CTFGame Game { get { return m_Game; } set { m_Game = value; } } + public int TeamID { get { return m_TeamID; } } + + public int Kills { get { return m_Kills; } set { m_Kills = value; } } + public int Captures { get { return m_Captures; } set { m_Captures = value; } } + + public int Score { get { return m_Score; } set { m_Score = value; } } + + private CTFPlayerInfo m_Leader; + + public CTFPlayerInfo Leader + { + get { return m_Leader; } + set { m_Leader = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public CTFBoard Board + { + get { return m_Board; } + set { m_Board = value; } + } + + public Dictionary Players + { + get { return m_Players; } + } + + public CTFPlayerInfo this[Mobile mob] + { + get + { + if ( mob == null ) + return null; + + CTFPlayerInfo val; + + if ( !m_Players.TryGetValue( mob, out val ) ) + m_Players[mob] = val = new CTFPlayerInfo( this, mob ); + + return val; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Color + { + get { return m_Color; } + set { m_Color = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Name + { + get { return m_Name; } + set { m_Name = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public CTFFlag Flag + { + get { return m_Flag; } + set { m_Flag = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D Origin + { + get { return m_Origin; } + set { m_Origin = value; } + } + + public CTFTeamInfo( int teamID ) + { + m_TeamID = teamID; + m_Players = new Dictionary(); + } + + public void Reset() + { + m_Kills = 0; + m_Captures = 0; + + m_Score = 0; + + m_Leader = null; + + m_Players.Clear(); + + if ( m_Flag != null ) + { + m_Flag.m_TeamInfo = this; + m_Flag.Hue = m_Color; + m_Flag.SendHome(); + } + + if ( m_Board != null ) + m_Board.m_TeamInfo = this; + } + + public CTFTeamInfo( int teamID, GenericReader ip ) + { + m_TeamID = teamID; + m_Players = new Dictionary(); + + int version = ip.ReadEncodedInt(); + + switch ( version ) + { + case 2: + { + m_Board = ip.ReadItem() as CTFBoard; + + goto case 1; + } + case 1: + { + m_Name = ip.ReadString(); + + goto case 0; + } + case 0: + { + m_Color = ip.ReadEncodedInt(); + + m_Flag = ip.ReadItem() as CTFFlag; + m_Origin = ip.ReadPoint3D(); + break; + } + } + } + + public void Serialize( GenericWriter op ) + { + op.WriteEncodedInt( 2 ); // version + + op.Write( m_Board ); + + op.Write( m_Name ); + + op.WriteEncodedInt( m_Color ); + + op.Write( m_Flag ); + op.Write( m_Origin ); + } + + public override string ToString() + { + return "..."; + } + } + + public sealed class CTFController : EventController + { + private CTFTeamInfo[] m_TeamInfo; + + private TimeSpan m_Duration; + + public CTFTeamInfo[] TeamInfo { get { return m_TeamInfo; } } + + [CommandProperty( AccessLevel.GameMaster )] + public CTFTeamInfo Team1 { get { return m_TeamInfo[0]; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public CTFTeamInfo Team2 { get { return m_TeamInfo[1]; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public CTFTeamInfo Team3 { get { return m_TeamInfo[2]; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public CTFTeamInfo Team4 { get { return m_TeamInfo[3]; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public CTFTeamInfo Team5 { get { return m_TeamInfo[4]; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public CTFTeamInfo Team6 { get { return m_TeamInfo[5]; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public CTFTeamInfo Team7 { get { return m_TeamInfo[6]; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public CTFTeamInfo Team8 { get { return m_TeamInfo[7]; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan Duration + { + get { return m_Duration; } + set { m_Duration = value; } + } + + public override string Title + { + get { return "CTF"; } + } + + public override string GetTeamName( int teamID ) + { + return m_TeamInfo[teamID % m_TeamInfo.Length].Name; + } + + public override EventGame Construct( DuelContext context ) + { + return new CTFGame( this, context ); + } + + [Constructable] + public CTFController() + { + Visible = false; + Movable = false; + + m_Duration = TimeSpan.FromMinutes( 30.0 ); + + m_TeamInfo = new CTFTeamInfo[8]; + + for ( int i = 0; i < m_TeamInfo.Length; ++i ) + m_TeamInfo[i] = new CTFTeamInfo( i ); + } + + public CTFController( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); + + writer.Write( m_Duration ); + + writer.WriteEncodedInt( m_TeamInfo.Length ); + + for ( int i = 0; i < m_TeamInfo.Length; ++i ) + m_TeamInfo[i].Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 2: + { + m_Duration = reader.ReadTimeSpan(); + + goto case 1; + } + case 1: + { + m_TeamInfo = new CTFTeamInfo[reader.ReadEncodedInt()]; + + for ( int i = 0; i < m_TeamInfo.Length; ++i ) + m_TeamInfo[i] = new CTFTeamInfo( i, reader ); + + break; + } + case 0: + { + m_TeamInfo = new CTFTeamInfo[8]; + + for ( int i = 0; i < m_TeamInfo.Length; ++i ) + m_TeamInfo[i] = new CTFTeamInfo( i ); + + break; + } + } + + if ( version < 2 ) + m_Duration = TimeSpan.FromMinutes( 30.0 ); + } + } + + public sealed class CTFGame : EventGame + { + public static void Initialize() + { + for ( int i = 0x7C9; i <= 0x7D0; ++i ) + TileData.ItemTable[i].Flags |= TileFlag.NoShoot; + } + + private CTFController m_Controller; + + public CTFController Controller { get { return m_Controller; } } + + public void Alert( string text ) + { + if ( m_Context.m_Tournament != null ) + m_Context.m_Tournament.Alert( text ); + + for ( int i = 0; i < m_Context.Participants.Count; ++i ) + { + Participant p = m_Context.Participants[i] as Participant; + + 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 CTFGame( CTFController controller, DuelContext context ) : base( context ) + { + m_Controller = controller; + } + + public Map Facet + { + get + { + if ( m_Context.Arena != null ) + return m_Context.Arena.Facet; + + return m_Controller.Map; + } + } + + public CTFTeamInfo GetTeamInfo( Mobile mob ) + { + int teamID = GetTeamID( mob ); + + if ( teamID >= 0 ) + return m_Controller.TeamInfo[teamID % m_Controller.TeamInfo.Length]; + + return null; + } + + public int GetTeamID( Mobile mob ) + { + PlayerMobile pm = mob as PlayerMobile; + + if ( pm == null ) + return -1; + + if ( pm.DuelContext == null || pm.DuelContext != m_Context ) + return -1; + + if ( pm.DuelPlayer == null || pm.DuelPlayer.Eliminated ) + 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, new TimerStateCallback( DelayBounce_Callback ), new object[] { mob, corpse } ); + } + + private void DelayBounce_Callback( object state ) + { + object[] states = (object[]) state; + Mobile mob = (Mobile) states[0]; + Container corpse = (Container) states[1]; + + DuelPlayer dp = null; + + if ( mob is PlayerMobile ) + dp = ( mob as PlayerMobile ).DuelPlayer; + + m_Context.RemoveAggressions( mob ); + + if ( dp != null && !dp.Eliminated ) + 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; + + Item[] flags = corpse.FindItemsByType( typeof( CTFFlag ), false ); + + for ( int i = 0; i < flags.Length; ++i ) + ( flags[i] as CTFFlag ).DropTo( mob, killer ); + + hadFlag = ( hadFlag || flags.Length > 0 ); + + if ( mob.Backpack != null ) + { + flags = mob.Backpack.FindItemsByType( typeof( CTFFlag ), false ); + + for ( int i = 0; i < flags.Length; ++i ) + ( flags[i] as CTFFlag ).DropTo( mob, killer ); + + hadFlag = ( hadFlag || flags.Length > 0 ); + } + + if ( killer != null && killer.Player ) + { + 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 == this.Facet ) + playerInfo.Score += 1; // fragged in base -- guarding + + for ( int i = 0; i < m_Controller.TeamInfo.Length; ++i ) + { + if ( m_Controller.TeamInfo[i] == teamInfo ) + continue; + + Mobile ourFlagCarrier = null; + + if ( m_Controller.TeamInfo[i].Flag != null ) + ourFlagCarrier = m_Controller.TeamInfo[i].Flag.RootParent as Mobile; + + if ( ourFlagCarrier != null && GetTeamInfo( ourFlagCarrier ) == teamInfo ) + { + for ( int j = 0; j < ourFlagCarrier.Aggressors.Count; ++j ) + { + AggressorInfo aggr = ourFlagCarrier.Aggressors[j] as AggressorInfo; + + if ( aggr == null || 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( typeof( CTFBoardGump ) ); + mob.SendGump( new CTFBoardGump( mob, this ) ); + + m_Context.Requip( mob, corpse ); + DelayBounce( TimeSpan.FromSeconds( 30.0 ), mob, corpse ); + + return false; + } + + private Timer m_FinishTimer; + + public override void OnStart() + { + for ( int i = 0; i < m_Controller.TeamInfo.Length; ++i ) + { + CTFTeamInfo teamInfo = m_Controller.TeamInfo[i]; + + teamInfo.Game = this; + teamInfo.Reset(); + } + + for ( int i = 0; i < m_Context.Participants.Count; ++i ) + ApplyHues( m_Context.Participants[i] as Participant, m_Controller.TeamInfo[i % 8].Color ); + + if ( m_FinishTimer != null ) + m_FinishTimer.Stop(); + + m_FinishTimer = Timer.DelayCall( m_Controller.Duration, new TimerCallback( Finish_Callback ) ); + } + + private void Finish_Callback() + { + List teams = new List(); + + for ( int i = 0; i < m_Context.Participants.Count; ++i ) + { + CTFTeamInfo teamInfo = m_Controller.TeamInfo[i % 8]; + + if ( teamInfo == null || teamInfo.Flag == null ) + continue; + + teams.Add( teamInfo ); + } + + teams.Sort( delegate( CTFTeamInfo a, CTFTeamInfo b ) + { + return b.Score - a.Score; + } ); + + Tournament tourny = m_Context.m_Tournament; + + StringBuilder sb = new StringBuilder(); + + if ( tourny != null && tourny.TournyType == TournyType.FreeForAll ) + { + sb.Append( m_Context.Participants.Count * tourny.PlayersPerParticipant ); + sb.Append( "-man FFA" ); + } + else if ( tourny != null && tourny.TournyType == TournyType.RandomTeam ) + { + sb.Append( tourny.ParticipantsPerMatch ); + sb.Append( "-team" ); + } + else if ( tourny != null && tourny.TournyType == TournyType.RedVsBlue ) + { + sb.Append( "Red v Blue" ); + } + else if ( tourny != null && tourny.TournyType == TournyType.Faction ) + { + sb.Append( tourny.ParticipantsPerMatch ); + sb.Append( "-team Faction" ); + } + else if ( tourny != null ) + { + for ( int i = 0; i < tourny.ParticipantsPerMatch; ++i ) + { + if ( sb.Length > 0 ) + sb.Append( 'v' ); + + sb.Append( tourny.PlayersPerParticipant ); + } + } + + if ( m_Controller != null ) + sb.Append( ' ' ).Append( m_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 = String.Format( "{0}, {1} team", item.Name, teams[i].Name.ToLower() ); + + 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] as Participant; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer dp = p.Players[j]; + + if ( dp != null && dp.Mobile != null ) + { + dp.Mobile.CloseGump( typeof( CTFBoardGump ) ); + 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] as Participant ); + } + + public override void OnStop() + { + for ( int i = 0; i < m_Controller.TeamInfo.Length; ++i ) + { + CTFTeamInfo teamInfo = m_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] as Participant, -1 ); + + if ( m_FinishTimer != null ) + m_FinishTimer.Stop(); + + m_FinishTimer = null; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/Games/DoubleDom.cs b/Scripts/Engines/ConPVP/Games/DoubleDom.cs new file mode 100644 index 000000000..1749f9a6d --- /dev/null +++ b/Scripts/Engines/ConPVP/Games/DoubleDom.cs @@ -0,0 +1,1250 @@ +using System; +using System.Collections; +using System.Text; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; +using Server.Gumps; +using System.Collections.Generic; + +namespace Server.Engines.ConPVP +{ + public sealed class DDBoard : Item + { + public DDTeamInfo m_TeamInfo; + + public override string DefaultName + { + get { return "scoreboard"; } + } + + [Constructable] + public DDBoard() + : base( 7774 ) + { + Movable = false; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_TeamInfo != null && m_TeamInfo.Game != null ) + { + from.CloseGump( typeof( DDBoardGump ) ); + from.SendGump( new DDBoardGump( from, m_TeamInfo.Game ) ); + } + } + + public DDBoard( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DDBoardGump : Gump + { + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", 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, false, false ); + else + AddHtml( x, y, width, height, Color( text, color ), false, false ); + } + + private const int LabelColor32 = 0xFFFFFF; + private const int BlackColor32 = 0x000000; + + private DDGame m_Game; + + public DDBoardGump( Mobile mob, DDGame game ) + : this( mob, game, null ) + { + } + + public DDBoardGump( Mobile mob, DDGame game, DDTeamInfo section ) + : base( 60, 60 ) + { + m_Game = game; + + DDTeamInfo ourTeam = game.GetTeamInfo( mob ); + + List entries = new List(); + + if ( section == null ) + { + for ( int i = 0; i < game.Context.Participants.Count; ++i ) + { + DDTeamInfo teamInfo = game.Controller.TeamInfo[i % game.Controller.TeamInfo.Length]; + + if ( teamInfo != null ) + entries.Add( teamInfo ); + } + } + else + { + foreach ( DDPlayerInfo 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( "DD 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 ) + { + DDTeamInfo teamInfo = entries[i] as DDTeamInfo; + + 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, String.Format( "{0}: {1}", LadderGump.Rank( 1 + i ), teamInfo.Name ), 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 ); + + DDPlayerInfo 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 ); + } + } + else + { + } + + AddButton( 314, height - 42, 247, 248, 1, GumpButtonType.Reply, 0 ); + } + } + + public sealed class DDPlayerInfo : IRankedCTF + { + private DDTeamInfo m_TeamInfo; + + private Mobile m_Player; + + private int m_Kills; + private int m_Captures; + + private int m_Score; + + public Mobile Player { get { return m_Player; } } + + public string Name + { + get { return m_Player.Name; } + } + + public int Kills + { + get + { + return m_Kills; + } + set + { + m_TeamInfo.Kills += ( value - m_Kills ); + m_Kills = value; + } + } + + public int Captures + { + get + { + return m_Captures; + } + set + { + m_TeamInfo.Captures += ( value - m_Captures ); + m_Captures = value; + } + } + + public int Score + { + get + { + return 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; + } + } + + public DDPlayerInfo( DDTeamInfo teamInfo, Mobile player ) + { + m_TeamInfo = teamInfo; + m_Player = player; + } + } + + [PropertyObject] + public sealed class DDTeamInfo : IRankedCTF + { + private DDGame m_Game; + private int m_TeamID; + + private int m_Color; + private string m_Name; + + private DDBoard m_Board; + + private Point3D m_Origin; + + private int m_Kills; + private int m_Captures; + + private int m_Score; + + private Dictionary m_Players; + + public string Name + { + get { return String.Format( "{0} Team", m_Name ); } + } + + public DDGame Game { get { return m_Game; } set { m_Game = value; } } + public int TeamID { get { return m_TeamID; } } + + public int Kills { get { return m_Kills; } set { m_Kills = value; } } + public int Captures { get { return m_Captures; } set { m_Captures = value; } } + + public int Score { get { return m_Score; } set { m_Score = value; } } + + private DDPlayerInfo m_Leader; + + public DDPlayerInfo Leader + { + get { return m_Leader; } + set { m_Leader = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DDBoard Board + { + get { return m_Board; } + set { m_Board = value; } + } + + public Dictionary Players + { + get { return m_Players; } + } + + public DDPlayerInfo this[Mobile mob] + { + get + { + if ( mob == null ) + return null; + + DDPlayerInfo val; + + if ( !m_Players.TryGetValue( mob, out val ) ) + m_Players[mob] = val = new DDPlayerInfo( this, mob ); + + return val; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Color + { + get { return m_Color; } + set { m_Color = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string TeamName + { + get { return m_Name; } + set { m_Name = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D Origin + { + get { return m_Origin; } + set { m_Origin = value; } + } + + public DDTeamInfo( int teamID ) + { + m_TeamID = teamID; + m_Players = new Dictionary(); + } + + public void Reset() + { + m_Kills = 0; + m_Captures = 0; + + m_Score = 0; + + m_Leader = null; + + m_Players.Clear(); + + if ( m_Board != null ) + m_Board.m_TeamInfo = this; + } + + public DDTeamInfo( int teamID, GenericReader ip ) + { + m_TeamID = teamID; + m_Players = new Dictionary(); + + int version = ip.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + m_Board = ip.ReadItem() as DDBoard; + m_Name = ip.ReadString(); + m_Color = ip.ReadEncodedInt(); + m_Origin = ip.ReadPoint3D(); + break; + } + } + } + + public void Serialize( GenericWriter op ) + { + op.WriteEncodedInt( 0 ); // version + + op.Write( m_Board ); + op.Write( m_Name ); + op.WriteEncodedInt( m_Color ); + op.Write( m_Origin ); + } + + public override string ToString() + { + return "..."; + } + } + + public sealed class DDController : EventController + { + private DDTeamInfo[] m_TeamInfo; + + private TimeSpan m_Duration; + + public DDTeamInfo[] TeamInfo { get { return m_TeamInfo; } } + + [CommandProperty( AccessLevel.GameMaster )] + public DDTeamInfo Team1 { get { return m_TeamInfo[0]; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public DDTeamInfo Team2 { get { return m_TeamInfo[1]; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public DDWayPoint PointA { get { return m_PointA; } set { m_PointA = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public DDWayPoint PointB { get { return m_PointB; } set { m_PointB = value; } } + + private DDWayPoint m_PointA, m_PointB; + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan Duration + { + get { return m_Duration; } + set { m_Duration = value; } + } + + public override string Title + { + get { return "DoubleDom"; } + } + + public override string GetTeamName( int teamID ) + { + return m_TeamInfo[teamID % m_TeamInfo.Length].Name; + } + + public override EventGame Construct( DuelContext context ) + { + return new DDGame( this, context ); + } + + public override string DefaultName { get { return "DD Controller"; } } + + [Constructable] + public DDController() + { + Visible = false; + Movable = false; + + m_Duration = TimeSpan.FromMinutes( 30.0 ); + + m_TeamInfo = new DDTeamInfo[2]; + + for ( int i = 0; i < m_TeamInfo.Length; ++i ) + m_TeamInfo[i] = new DDTeamInfo( i ); + } + + public DDController( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + + writer.Write( m_Duration ); + + writer.WriteEncodedInt( m_TeamInfo.Length ); + + for ( int i = 0; i < m_TeamInfo.Length; ++i ) + m_TeamInfo[i].Serialize( writer ); + + writer.Write( m_PointA ); + writer.Write( m_PointB ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Duration = reader.ReadTimeSpan(); + m_TeamInfo = new DDTeamInfo[reader.ReadEncodedInt()]; + + for ( int i = 0; i < m_TeamInfo.Length; ++i ) + m_TeamInfo[i] = new DDTeamInfo( i, reader ); + + m_PointA = reader.ReadItem() as DDWayPoint; + m_PointB = reader.ReadItem() as DDWayPoint; + + break; + } + } + } + } + + public sealed class DDGame : EventGame + { + private DDController m_Controller; + + public DDController Controller { get { return m_Controller; } } + + public void Alert( string text ) + { + if ( m_Context.m_Tournament != null ) + m_Context.m_Tournament.Alert( text ); + + for ( int i = 0; i < m_Context.Participants.Count; ++i ) + { + Participant p = m_Context.Participants[i] as Participant; + + 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 DDGame( DDController controller, DuelContext context ) : base( context ) + { + m_Controller = controller; + } + + public Map Facet + { + get + { + if ( m_Context.Arena != null ) + return m_Context.Arena.Facet; + + return m_Controller.Map; + } + } + + public DDTeamInfo GetTeamInfo( Mobile mob ) + { + int teamID = GetTeamID( mob ); + + if ( teamID >= 0 ) + return m_Controller.TeamInfo[teamID % m_Controller.TeamInfo.Length]; + + return null; + } + + public int GetTeamID( Mobile mob ) + { + PlayerMobile pm = mob as PlayerMobile; + + if ( pm == null ) + return -1; + + if ( pm.DuelContext == null || pm.DuelContext != m_Context ) + return -1; + + if ( pm.DuelPlayer == null || pm.DuelPlayer.Eliminated ) + return -1; + + return pm.DuelContext.Participants.IndexOf( pm.DuelPlayer.Participant ); + } + + public int GetColor( Mobile mob ) + { + DDTeamInfo 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, new TimerStateCallback( DelayBounce_Callback ), new object[] { mob, corpse } ); + } + + private void DelayBounce_Callback( object state ) + { + object[] states = (object[]) state; + Mobile mob = (Mobile) states[0]; + Container corpse = (Container) states[1]; + + DuelPlayer dp = null; + + if ( mob is PlayerMobile ) + dp = ( mob as PlayerMobile ).DuelPlayer; + + m_Context.RemoveAggressions( mob ); + + if ( dp != null && !dp.Eliminated ) + 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 ); + + if ( killer != null && killer.Player ) + { + DDTeamInfo teamInfo = GetTeamInfo( killer ); + DDTeamInfo victInfo = GetTeamInfo( mob ); + + if ( teamInfo != null && teamInfo != victInfo ) + { + DDPlayerInfo playerInfo = teamInfo[killer]; + + if ( playerInfo != null ) + { + playerInfo.Kills += 1; + playerInfo.Score += 1; // base frag + + // extra points for killing someone on the waypoint + if ( this.Controller.PointA != null ) + { + if ( mob.InRange( this.Controller.PointA, 2 ) ) + playerInfo.Score += 1; + } + + if ( this.Controller.PointB != null ) + { + if ( mob.InRange( this.Controller.PointB, 2 ) ) + playerInfo.Score += 1; + } + } + + playerInfo = victInfo[mob]; + if ( playerInfo != null ) + playerInfo.Score -= 1; + } + } + + mob.CloseGump( typeof( DDBoardGump ) ); + mob.SendGump( new DDBoardGump( mob, this ) ); + + m_Context.Requip( mob, corpse ); + DelayBounce( TimeSpan.FromSeconds( 30.0 ), mob, corpse ); + + return false; + } + + private Timer m_FinishTimer; + + public override void OnStart() + { + m_Capturable = true; + + if ( m_CaptureTimer != null ) + { + m_CaptureTimer.Stop(); + m_CaptureTimer = null; + } + + if ( m_UncaptureTimer != null ) + { + m_UncaptureTimer.Stop(); + m_UncaptureTimer = null; + } + + for ( int i = 0; i < m_Controller.TeamInfo.Length; ++i ) + { + DDTeamInfo teamInfo = m_Controller.TeamInfo[i]; + + teamInfo.Game = this; + teamInfo.Reset(); + } + + if ( m_Controller.PointA != null ) + m_Controller.PointA.Game = this; + + if ( m_Controller.PointB != null ) + m_Controller.PointB.Game = this; + + for ( int i = 0; i < m_Context.Participants.Count; ++i ) + ApplyHues( m_Context.Participants[i] as Participant, m_Controller.TeamInfo[i % m_Controller.TeamInfo.Length].Color ); + + if ( m_FinishTimer != null ) + m_FinishTimer.Stop(); + + m_FinishTimer = Timer.DelayCall( m_Controller.Duration, new TimerCallback( Finish_Callback ) ); + } + + private void Finish_Callback() + { + List teams = new List(); + + for ( int i = 0; i < m_Context.Participants.Count; ++i ) + { + DDTeamInfo teamInfo = m_Controller.TeamInfo[i % m_Controller.TeamInfo.Length]; + + if ( teamInfo != null ) + teams.Add( teamInfo ); + } + + teams.Sort( delegate( DDTeamInfo a, DDTeamInfo b ) + { + return b.Score - a.Score; + } ); + + Tournament tourny = m_Context.m_Tournament; + + StringBuilder sb = new StringBuilder(); + + if ( tourny != null && tourny.TournyType == TournyType.FreeForAll ) + { + sb.Append( m_Context.Participants.Count * tourny.PlayersPerParticipant ); + sb.Append( "-man FFA" ); + } + else if ( tourny != null && tourny.TournyType == TournyType.RandomTeam ) + { + sb.Append( tourny.ParticipantsPerMatch ); + sb.Append( "-team" ); + } + else if ( tourny != null && tourny.TournyType == TournyType.RedVsBlue ) + { + sb.Append( "Red v Blue" ); + } + else if ( tourny != null && tourny.TournyType == TournyType.Faction ) + { + sb.Append( tourny.ParticipantsPerMatch ); + sb.Append( "-team Faction" ); + } + else if ( tourny != null ) + { + for ( int i = 0; i < tourny.ParticipantsPerMatch; ++i ) + { + if ( sb.Length > 0 ) + sb.Append( 'v' ); + + sb.Append( tourny.PlayersPerParticipant ); + } + } + + if ( m_Controller != null ) + sb.Append( ' ' ).Append( m_Controller.Title ); + + string title = sb.ToString(); + + DDTeamInfo winner = (DDTeamInfo)( 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; + + DDPlayerInfo leader = ((DDTeamInfo)teams[i]).Leader; + + foreach ( DDPlayerInfo pl in ((DDTeamInfo)teams[i]).Players.Values ) + { + Mobile mob = pl.Player; + + if ( mob == null ) + continue; + + //"Red v Blue DD 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 = String.Format( "{0}, {1} team", item.Name, ((DDTeamInfo)teams[i]).Name.ToLower() ); + + 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] as Participant; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer dp = p.Players[j]; + + if ( dp != null && dp.Mobile != null ) + { + dp.Mobile.CloseGump( typeof( DDBoardGump ) ); + dp.Mobile.SendGump( new DDBoardGump( 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] as Participant ); + } + + public override void OnStop() + { + for ( int i = 0; i < m_Controller.TeamInfo.Length; ++i ) + { + DDTeamInfo teamInfo = m_Controller.TeamInfo[i]; + + if ( teamInfo.Board != null ) + teamInfo.Board.m_TeamInfo = null; + + teamInfo.Game = null; + } + + if ( m_Controller.PointA != null ) + m_Controller.PointA.Game = null; + + if ( m_Controller.PointB != null ) + m_Controller.PointB.Game = null; + + m_Capturable = false; + + if ( m_CaptureTimer != null ) + { + m_CaptureTimer.Stop(); + m_CaptureTimer = null; + } + + if ( m_UncaptureTimer != null ) + { + m_UncaptureTimer.Stop(); + m_UncaptureTimer = null; + } + + for ( int i = 0; i < m_Context.Participants.Count; ++i ) + ApplyHues( m_Context.Participants[i] as Participant, -1 ); + + if ( m_FinishTimer != null ) + m_FinishTimer.Stop(); + + m_FinishTimer = null; + } + + private bool m_Capturable = true; + private Timer m_CaptureTimer = null; + private Timer m_UncaptureTimer = null; + private int m_CapStage = 0; + + public void Dominate( DDWayPoint point, Mobile from, DDTeamInfo team ) + { + if ( point == null || from == null || team == null || !m_Capturable ) + return; + + bool wasDom = ( m_Controller.PointA != null && m_Controller.PointB != null && + m_Controller.PointA.TeamOwner == m_Controller.PointB.TeamOwner && m_Controller.PointA.TeamOwner != null ); + + point.TeamOwner = team; + Alert( "{0} has captured {1}!", team.Name, point.Name ); + + bool isDom = ( m_Controller.PointA != null && m_Controller.PointB != null && + m_Controller.PointA.TeamOwner == m_Controller.PointB.TeamOwner && m_Controller.PointA.TeamOwner != null ); + + if ( wasDom && !isDom ) + { + Alert( "Domination averted!" ); + + if ( m_Controller.PointA != null ) + m_Controller.PointA.SetNonCaptureHue(); + + if ( m_Controller.PointB != null ) + m_Controller.PointB.SetNonCaptureHue(); + + if ( m_CaptureTimer != null ) + m_CaptureTimer.Stop(); + m_CaptureTimer = null; + } + + if ( !wasDom && isDom ) + { + m_CapStage = 0; + m_CaptureTimer = Timer.DelayCall( TimeSpan.Zero, TimeSpan.FromSeconds( 1.0 ), new TimerCallback( CaptureTick ) ); + m_CaptureTimer.Start(); + } + } + + private void CaptureTick() + { + DDTeamInfo team = null; + + if ( m_Controller.PointA != null && m_Controller.PointA.TeamOwner != null ) + team = m_Controller.PointA.TeamOwner; + else if ( m_Controller.PointB != null && m_Controller.PointB.TeamOwner != null ) + team = m_Controller.PointB.TeamOwner; + + if ( team == null ) + { + m_Capturable = true; + if ( m_CaptureTimer != null ) + m_CaptureTimer.Stop(); + m_CaptureTimer = null; + return; + } + + if ( ++m_CapStage < 10 ) + { + Alert( "{0} is dominating... {1}", team.Name, 10 - m_CapStage ); + + if ( m_Controller.PointA != null ) + m_Controller.PointA.SetCaptureHue( m_CapStage ); + + if ( m_Controller.PointB != null ) + m_Controller.PointB.SetCaptureHue( m_CapStage ); + } + else + { + Alert( "{0} has scored!", team.Name ); + + team.Score += 100; + team.Captures += 1; + + m_Capturable = false; + m_CapStage = 0; + m_CaptureTimer.Stop(); + m_CaptureTimer = null; + + if ( m_Controller.PointA != null ) + { + m_Controller.PointA.TeamOwner = null; + m_Controller.PointA.SetUncapturableHue(); + } + + if ( m_Controller.PointB != null ) + { + m_Controller.PointB.TeamOwner = null; + m_Controller.PointB.SetUncapturableHue(); + } + + m_UncaptureTimer = Timer.DelayCall( TimeSpan.FromSeconds( 30.0 ), new TimerCallback( UncaptureTick ) ); + m_UncaptureTimer.Start(); + } + } + + private void UncaptureTick() + { + m_Capturable = true; + + if ( m_CaptureTimer != null ) + { + m_CaptureTimer.Stop(); + m_CaptureTimer = null; + } + + if ( m_UncaptureTimer != null ) + { + m_UncaptureTimer.Stop(); + m_UncaptureTimer = null; + } + + if ( m_Controller.PointA != null ) + { + m_Controller.PointA.TeamOwner = null; + m_Controller.PointA.SetNonCaptureHue(); + } + + if ( m_Controller.PointB != null ) + { + m_Controller.PointB.TeamOwner = null; + m_Controller.PointB.SetNonCaptureHue(); + } + } + } + + public class DDWayPoint : BaseAddon + { + private DDTeamInfo m_TeamOwner; + private DDGame m_Game; + + [Constructable] + public DDWayPoint() + { + this.ItemID = 0x519; + this.Visible = true; + this.Name = "SET MY NAME"; + + AddComponent( new DDStep( 0x7A8 ), -1, -1, -5 ); + AddComponent( new DDStep( 0x7A6 ), 0, -1, -5 ); + AddComponent( new DDStep( 0x7AA ), 1, -1, -5 ); + + AddComponent( new DDStep( 0x7A5 ), 1, 0, -5 ); + + AddComponent( new DDStep( 0x7A9 ), 1, 1, -5 ); + AddComponent( new DDStep( 0x7A4 ), 0, 1, -5 ); + AddComponent( new DDStep( 0x7AB ), -1, 1, -5 ); + + AddComponent( new DDStep( 0x7A7 ), -1, 0, -5 ); + + SetUncapturableHue(); + } + + public DDWayPoint( Serial serial ) : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool ShareHue{ get{ return false; } } + + public DDGame Game + { + get{ return m_Game; } + set + { + m_Game = value; + m_TeamOwner = null; + + if ( m_Game != null ) + SetNonCaptureHue(); + else + SetUncapturableHue(); + } + } + + public DDTeamInfo TeamOwner + { + get{ return m_TeamOwner; } + set + { + m_TeamOwner = value; + + SetNonCaptureHue(); + } + } + + public const int UncapturableHue = 0x497; + public const int NonCapturedHue = 0x38A; + + public void SetUncapturableHue() + { + for (int i=0;i= m.StamMax) + m.Stam -= 5; + } + + return false; + } + + public override bool OnMoveOff(Mobile m) + { + if (base.OnMoveOff(m)) + { + if (m_King == m) + DeKingify(); + + return true; + } + else + { + return false; + } + } + + public virtual void OnKingDied(Mobile king, KHTeamInfo kingTeam, Mobile killer, KHTeamInfo killerTeam) + { + if (m_Game != null && CapturesSoFar > 0 && killer != null && king != null && kingTeam != null && killerTeam != null) + { + string kingName = king.Name; + if (kingName == null) + kingName = ""; + string killerName = killer.Name; + if (killerName == null) + killerName = ""; + + m_Game.Alert("{0} ({1}) was dethroned by {2} ({3})!", kingName, kingTeam.Name, killerName, killerTeam.Name); + } + + DeKingify(); + } + + private void DeKingify() + { + PublicOverheadMessage(MessageType.Regular, 0x0481, false, "Free!"); + + if (m_KingTimer != null) + m_KingTimer.Stop(); + + m_King = null; + } + + private void ReKingify(Mobile m) + { + KHTeamInfo ti = null; + if (m_Game == null || m == null) + return; + + ti = m_Game.GetTeamInfo(m); + if (ti == null) + return; + + m_King = m; + + if (m_KingTimer == null) + m_KingTimer = new KingTimer(this); + m_KingTimer.Stop(); + m_KingTimer.StartHillTicker(); + + if (m_King.Name != null) + PublicOverheadMessage(MessageType.Regular, 0x0481, false, String.Format("Taken by {0}!", m_King.Name)); + } + + private class KingTimer : Timer + { + private HillOfTheKing m_Hill; + private int m_Total; + private int m_Counter; + + public int Captures { get { return m_Total; } } + + public KingTimer(HillOfTheKing hill) + : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) + { + m_Hill = hill; + m_Total = 0; + m_Counter = 0; + + Priority = TimerPriority.FiftyMS; + } + + public void StartHillTicker() + { + m_Total = 0; + m_Counter = 0; + + Start(); + } + + protected override void OnTick() + { + KHTeamInfo ti = null; + KHPlayerInfo pi = null; + + if (m_Hill == null || m_Hill.Deleted || m_Hill.Game == null) + { + Stop(); + return; + } + + if (m_Hill.King == null || m_Hill.King.Deleted || !m_Hill.King.Alive) + { + m_Hill.DeKingify(); + Stop(); + return; + } + + ti = m_Hill.Game.GetTeamInfo(m_Hill.King); + if (ti != null) + pi = ti[m_Hill.King]; + + if (ti == null || pi == null) + { + // error, bail + m_Hill.DeKingify(); + Stop(); + return; + } + + m_Counter++; + + m_Hill.King.RevealingAction(); + + if (m_Counter >= m_Hill.ScoreInterval) + { + string hill = m_Hill.Name; + string king = m_Hill.King.Name; + if (king == null) + king = ""; + + if (hill == null || hill == "") + hill = "the hill"; + + m_Hill.Game.Alert("{0} ({1}) is king of {2}!", king, ti.Name, hill); + + m_Hill.PublicOverheadMessage(MessageType.Regular, 0x0481, false, "Capture!"); + + pi.Captures++; + m_Total++; + + pi.Score += m_Counter; + + m_Counter = 0; + } + else + { + m_Hill.PublicOverheadMessage(MessageType.Regular, 0x0481, false, (m_Hill.ScoreInterval - m_Counter).ToString()); + } + } + } + } + + public class KHBoard : Item + { + public KHGame m_Game; + private KHController m_Controller; + + [Constructable] + public KHBoard() + : base(7774) + { + Name = "King of the Hill Scoreboard"; + Movable = false; + } + + [CommandProperty(AccessLevel.GameMaster)] + public KHController Controller + { + get { return m_Controller; } + set + { + if (m_Controller != value) + { + if (m_Controller != null) + m_Controller.RemoveBoard(this); + m_Controller = value; + if (m_Controller != null) + m_Controller.AddBoard(this); + } + } + } + + public override void OnDoubleClick(Mobile from) + { + if (m_Game != null) + { + from.CloseGump(typeof(KHBoardGump)); + from.SendGump(new KHBoardGump(from, m_Game)); + } + else + { + from.SendMessage("There is no King of the Hill game in progress."); + } + } + + public KHBoard(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + + writer.Write(m_Controller); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Controller = reader.ReadItem() as KHController; + break; + } + } + } + } + + public sealed class KHBoardGump : Gump + { + public string Center(string text) + { + return String.Format("
{0}
", text); + } + + public string Color(string text, int color) + { + return String.Format("{1}", 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, false, false); + else + AddHtml(x, y, width, height, Color(text, color), false, false); + } + + private const int LabelColor32 = 0xFFFFFF; + private const int BlackColor32 = 0x000000; + + private KHGame m_Game; + + public KHBoardGump(Mobile mob, KHGame game) + : base(60, 60) + { + m_Game = game; + + KHTeamInfo ourTeam = game.GetTeamInfo(mob); + + ArrayList entries = new ArrayList(); + + for (int i = 0; i < game.Context.Participants.Count; ++i) + { + KHTeamInfo teamInfo = game.Controller.TeamInfo[i % game.Controller.TeamInfo.Length]; + + if (teamInfo == null) + continue; + + entries.Add(teamInfo); + } + + entries.Sort(); + /* + delegate( IRankedCTF a, IRankedCTF b ) + { + return b.Score - a.Score; + } );*/ + + int 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("King of the Hill Scoreboard"), LabelColor32, BlackColor32); + + AddImageTiled(32, 50, 264, 1, 9107); + AddImageTiled(42, 52, 264, 1, 9157); + + for (int i = 0; i < entries.Count; ++i) + { + KHTeamInfo teamInfo = entries[i] as KHTeamInfo; + + 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, String.Format("{0}: {1}", LadderGump.Rank(1 + i), teamInfo.Name), 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); + + string leader = null; + if (teamInfo.Leader != null) + leader = teamInfo.Leader.Name; + if (leader == null) + leader = "(none)"; + + AddBorderedText(235 + 10, 85 + (i * 75), 250, 20, "Leader:", 0xFFC000, BlackColor32); + AddBorderedText(235 + 15, 105 + (i * 75), 250, 20, leader, 0xFFC000, BlackColor32); + } + + AddButton(314, height - 42, 247, 248, 1, GumpButtonType.Reply, 0); + } + } + + public sealed class KHPlayerInfo : IRankedCTF, IComparable + { + private KHTeamInfo m_TeamInfo; + + private Mobile m_Player; + + private int m_Kills; + private int m_Captures; + private int m_Score; + + public KHPlayerInfo(KHTeamInfo teamInfo, Mobile player) + { + m_TeamInfo = teamInfo; + m_Player = player; + } + + public Mobile Player { get { return m_Player; } } + + public int CompareTo(object obj) + { + KHPlayerInfo pi = (KHPlayerInfo)obj; + int res = pi.Score.CompareTo(this.Score); + if (res == 0) + { + res = pi.Captures.CompareTo(this.Captures); + + if (res == 0) + res = pi.Kills.CompareTo(this.Kills); + } + return res; + } + + public string Name + { + get + { + if (m_Player == null || m_Player.Name == null) + return ""; + return m_Player.Name; + } + } + + public int Kills + { + get + { + return m_Kills; + } + set + { + m_TeamInfo.Kills += (value - m_Kills); + m_Kills = value; + } + } + + public int Captures + { + get + { + return m_Captures; + } + set + { + m_TeamInfo.Captures += (value - m_Captures); + m_Captures = value; + } + } + + public int Score + { + get + { + return 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 KHTeamInfo : IRankedCTF, IComparable + { + private KHGame m_Game; + private int m_TeamID; + + private int m_Color; + private string m_Name; + + private int m_Kills; + private int m_Captures; + + private int m_Score; + + private Hashtable m_Players; + + public int CompareTo(object obj) + { + KHTeamInfo ti = (KHTeamInfo)obj; + int res = ti.Score.CompareTo(this.Score); + if (res == 0) + { + res = ti.Captures.CompareTo(this.Captures); + + if (res == 0) + res = ti.Kills.CompareTo(this.Kills); + } + return res; + } + + public string Name + { + get + { + if (m_Name == null) + return "(null) Team"; + return String.Format("{0} Team", m_Name); + } + } + + public KHGame Game { get { return m_Game; } set { m_Game = value; } } + public int TeamID { get { return m_TeamID; } } + + public int Kills { get { return m_Kills; } set { m_Kills = value; } } + public int Captures { get { return m_Captures; } set { m_Captures = value; } } + public int Score { get { return m_Score; } set { m_Score = value; } } + + private KHPlayerInfo m_Leader; + + public KHPlayerInfo Leader + { + get { return m_Leader; } + set { m_Leader = value; } + } + + public Hashtable Players + { + get { return m_Players; } + } + + public KHPlayerInfo this[Mobile mob] + { + get + { + if (mob == null) + return null; + + KHPlayerInfo val = m_Players[mob] as KHPlayerInfo; + + if (val == null) + m_Players[mob] = val = new KHPlayerInfo(this, mob); + + return val; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Color + { + get { return m_Color; } + set { m_Color = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string TeamName + { + get { return m_Name; } + set { m_Name = value; } + } + + public KHTeamInfo(int teamID) + { + m_TeamID = teamID; + m_Players = new Hashtable(); + } + + public void Reset() + { + m_Kills = 0; + m_Captures = 0; + m_Score = 0; + + m_Leader = null; + + m_Players.Clear(); + } + + public KHTeamInfo(int teamID, GenericReader ip) + { + m_TeamID = teamID; + m_Players = new Hashtable(); + + int version = ip.ReadEncodedInt(); + + switch (version) + { + case 0: + { + m_Name = ip.ReadString(); + m_Color = ip.ReadEncodedInt(); + break; + } + } + } + + public void Serialize(GenericWriter op) + { + op.WriteEncodedInt(0); // version + + op.Write(m_Name); + op.WriteEncodedInt(m_Color); + } + + public override string ToString() + { + if (m_Name != null) + return String.Format("({0}) ...", this.Name); + else + return "..."; + } + } + + public sealed class KHController : EventController + { + private KHTeamInfo[] m_TeamInfo; + private HillOfTheKing[] m_Hills; + private ArrayList m_Boards; + private TimeSpan m_Duration; + private int m_ScoreInterval; + + public KHTeamInfo[] TeamInfo { get { return m_TeamInfo; } } + + [CommandProperty(AccessLevel.GameMaster)] + public KHTeamInfo Team1_W { get { return m_TeamInfo[0]; } set { } } + + [CommandProperty(AccessLevel.GameMaster)] + public KHTeamInfo Team2_E { get { return m_TeamInfo[1]; } set { } } + + [CommandProperty(AccessLevel.GameMaster)] + public KHTeamInfo Team3_N { get { return m_TeamInfo[2]; } set { } } + + [CommandProperty(AccessLevel.GameMaster)] + public KHTeamInfo Team4_S { get { return m_TeamInfo[3]; } set { } } + + [CommandProperty(AccessLevel.GameMaster)] + public KHTeamInfo Team5_NW { get { return m_TeamInfo[4]; } set { } } + + [CommandProperty(AccessLevel.GameMaster)] + public KHTeamInfo Team6_SE { get { return m_TeamInfo[5]; } set { } } + + [CommandProperty(AccessLevel.GameMaster)] + public KHTeamInfo Team7_SW { get { return m_TeamInfo[6]; } set { } } + + [CommandProperty(AccessLevel.GameMaster)] + public KHTeamInfo Team8_NE { get { return m_TeamInfo[7]; } set { } } + + public HillOfTheKing[] Hills { get { return m_Hills; } } + + [CommandProperty(AccessLevel.GameMaster)] + public HillOfTheKing Hill1 { get { return m_Hills[0]; } set { m_Hills[0] = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public HillOfTheKing Hill2 { get { return m_Hills[1]; } set { m_Hills[1] = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public HillOfTheKing Hill3 { get { return m_Hills[2]; } set { m_Hills[2] = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public HillOfTheKing Hill4 { get { return m_Hills[3]; } set { m_Hills[3] = value; } } + + public ArrayList Boards { get { return m_Boards; } } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan Duration + { + get { return m_Duration; } + set { m_Duration = value; } + } + + public override string Title + { + get { return "King of the Hill"; } + } + + public override string GetTeamName(int teamID) + { + return m_TeamInfo[teamID % m_TeamInfo.Length].Name; + } + + public override EventGame Construct(DuelContext context) + { + return new KHGame(this, context); + } + + public void RemoveBoard(KHBoard b) + { + if (b != null) + { + m_Boards.Remove(b); + b.m_Game = null; + } + } + + public void AddBoard(KHBoard b) + { + if (b != null) + m_Boards.Add(b); + } + + [Constructable] + public KHController() + { + Visible = false; + Movable = false; + + Name = "King of the Hill Controller"; + + m_Duration = TimeSpan.FromMinutes(30.0); + m_Boards = new ArrayList(); + m_Hills = new HillOfTheKing[4]; + m_TeamInfo = new KHTeamInfo[8]; + + for (int i = 0; i < m_TeamInfo.Length; ++i) + m_TeamInfo[i] = new KHTeamInfo(i); + } + + public KHController(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + + writer.WriteEncodedInt(m_ScoreInterval); + writer.Write(m_Duration); + + writer.WriteItemList(m_Boards, true); + + writer.WriteEncodedInt(m_Hills.Length); + for (int i = 0; i < m_Hills.Length; ++i) + writer.Write(m_Hills[i]); + + writer.WriteEncodedInt(m_TeamInfo.Length); + for (int i = 0; i < m_TeamInfo.Length; ++i) + m_TeamInfo[i].Serialize(writer); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_ScoreInterval = reader.ReadEncodedInt(); + + m_Duration = reader.ReadTimeSpan(); + + m_Boards = reader.ReadItemList(); + + m_Hills = new HillOfTheKing[reader.ReadEncodedInt()]; + for (int i = 0; i < m_Hills.Length; ++i) + m_Hills[i] = reader.ReadItem() as HillOfTheKing; + + m_TeamInfo = new KHTeamInfo[reader.ReadEncodedInt()]; + for (int i = 0; i < m_TeamInfo.Length; ++i) + m_TeamInfo[i] = new KHTeamInfo(i, reader); + + break; + } + } + } + } + + public sealed class KHGame : EventGame + { + private KHController m_Controller; + + public KHController Controller { get { return m_Controller; } } + + public override bool CantDoAnything(Mobile mob) + { + if (mob != null && GetTeamInfo(mob) != null && m_Controller != null) + { + for (int i = 0; i < m_Controller.Hills.Length; i++) + { + if (m_Controller.Hills[i] != null && m_Controller.Hills[i].King == mob) + return true; + } + } + + return false; + } + + public void Alert(string text) + { + if (m_Context.m_Tournament != null) + m_Context.m_Tournament.Alert(text); + + for (int i = 0; i < m_Context.Participants.Count; ++i) + { + Participant p = m_Context.Participants[i] as Participant; + + 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 KHGame(KHController controller, DuelContext context) + : base(context) + { + m_Controller = controller; + } + + public Map Facet + { + get + { + if (m_Context != null && m_Context.Arena != null) + return m_Context.Arena.Facet; + + return m_Controller.Map; + } + } + + public KHTeamInfo GetTeamInfo(Mobile mob) + { + int teamID = GetTeamID(mob); + + if (teamID >= 0) + return m_Controller.TeamInfo[teamID % m_Controller.TeamInfo.Length]; + + return null; + } + + public int GetTeamID(Mobile mob) + { + PlayerMobile pm = mob as PlayerMobile; + + if (pm == null) + { + if (mob is BaseCreature) + return ((BaseCreature)mob).Team - 1; + else + return -1; + } + + if (pm.DuelContext == null || pm.DuelContext != m_Context) + return -1; + + if (pm.DuelPlayer == null || pm.DuelPlayer.Eliminated) + return -1; + + return pm.DuelContext.Participants.IndexOf(pm.DuelPlayer.Participant); + } + + public int GetColor(Mobile mob) + { + KHTeamInfo 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, new TimerStateCallback(DelayBounce_Callback), new object[] { mob, corpse }); + } + + private void DelayBounce_Callback(object state) + { + object[] states = (object[])state; + Mobile mob = (Mobile)states[0]; + Container corpse = (Container)states[1]; + + DuelPlayer dp = null; + + if (mob is PlayerMobile) + dp = (mob as PlayerMobile).DuelPlayer; + + m_Context.RemoveAggressions(mob); + + if (dp != null && !dp.Eliminated) + 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; + + if (corpse != null && !corpse.Deleted) + Timer.DelayCall(TimeSpan.FromSeconds(30), new TimerCallback(corpse.Delete)); + } + + public override bool OnDeath(Mobile mob, Container corpse) + { + Mobile killer = mob.FindMostRecentDamager(false); + KHTeamInfo teamInfo = null; + KHTeamInfo victInfo = GetTeamInfo(mob); + int bonus = 0; + + if (killer != null && killer.Player) + teamInfo = GetTeamInfo(killer); + + for (int i = 0; i < m_Controller.Hills.Length; i++) + { + if (m_Controller.Hills[i] == null) + continue; + + if (m_Controller.Hills[i].King == mob) + { + bonus += m_Controller.Hills[i].CapturesSoFar; + m_Controller.Hills[i].OnKingDied(mob, victInfo, killer, teamInfo); + } + + if (m_Controller.Hills[i].King == killer) + bonus += 2; + } + + if (teamInfo != null && teamInfo != victInfo) + { + KHPlayerInfo playerInfo = teamInfo[killer]; + + if (playerInfo != null) + { + playerInfo.Kills += 1; + playerInfo.Score += 1 + bonus; + } + } + + mob.CloseGump(typeof(KHBoardGump)); + mob.SendGump(new KHBoardGump(mob, this)); + + m_Context.Requip(mob, corpse); + DelayBounce(TimeSpan.FromSeconds(30.0), mob, corpse); + + return false; + } + + private Timer m_FinishTimer; + + public override void OnStart() + { + for (int i = 0; i < m_Controller.TeamInfo.Length; ++i) + { + KHTeamInfo teamInfo = m_Controller.TeamInfo[i]; + + teamInfo.Game = this; + teamInfo.Reset(); + } + + for (int i = 0; i < m_Context.Participants.Count; ++i) + ApplyHues(m_Context.Participants[i] as Participant, m_Controller.TeamInfo[i % m_Controller.TeamInfo.Length].Color); + + if (m_FinishTimer != null) + m_FinishTimer.Stop(); + + for (int i = 0; i < m_Controller.Hills.Length; i++) + { + if (m_Controller.Hills[i] != null) + m_Controller.Hills[i].Game = this; + } + + foreach (KHBoard board in m_Controller.Boards) + { + if (board != null && !board.Deleted) + board.m_Game = this; + } + + m_FinishTimer = Timer.DelayCall(m_Controller.Duration, new TimerCallback(Finish_Callback)); + } + + private void Finish_Callback() + { + ArrayList teams = new ArrayList(); + + for (int i = 0; i < m_Context.Participants.Count; ++i) + { + KHTeamInfo teamInfo = m_Controller.TeamInfo[i % m_Controller.TeamInfo.Length]; + + if (teamInfo == null) + continue; + + teams.Add(teamInfo); + } + + teams.Sort(); + + Tournament tourny = m_Context.m_Tournament; + + StringBuilder sb = new StringBuilder(); + + if (tourny != null && tourny.TournyType == TournyType.FreeForAll) + { + sb.Append(m_Context.Participants.Count * tourny.PlayersPerParticipant); + sb.Append("-man FFA"); + } + else if (tourny != null && tourny.TournyType == TournyType.RandomTeam) + { + sb.Append(tourny.ParticipantsPerMatch); + sb.Append("-team"); + } + else if (tourny != null && tourny.TournyType == TournyType.RedVsBlue) + { + sb.Append("Red v Blue"); + } + else if (tourny != null) + { + for (int i = 0; i < tourny.ParticipantsPerMatch; ++i) + { + if (sb.Length > 0) + sb.Append('v'); + + sb.Append(tourny.PlayersPerParticipant); + } + } + + if (m_Controller != null) + sb.Append(' ').Append(m_Controller.Title); + + string title = sb.ToString(); + + KHTeamInfo winner = (KHTeamInfo)(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; + + KHPlayerInfo leader = ((KHTeamInfo)teams[i]).Leader; + + foreach (KHPlayerInfo pl in ((KHTeamInfo)teams[i]).Players.Values) + { + Mobile mob = pl.Player; + + if (mob == null) + continue; + + 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"); + + 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 = String.Format("{0}, {1}", item.Name, ((KHTeamInfo)teams[i]).Name.ToLower()); + + 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 game.", rank.ToString().ToLower(), cash); + } + else + { + mob.SendMessage("You have been awarded a {0} trophy for your participation in this game.", rank.ToString().ToLower()); + } + } + } + + for (int i = 0; i < m_Context.Participants.Count; ++i) + { + Participant p = m_Context.Participants[i] as Participant; + + if (p == null || p.Players == null) + continue; + + for (int j = 0; j < p.Players.Length; ++j) + { + DuelPlayer dp = p.Players[j]; + + if (dp != null && dp.Mobile != null) + { + dp.Mobile.CloseGump(typeof(KHBoardGump)); + dp.Mobile.SendGump(new KHBoardGump(dp.Mobile, this)); + } + } + + if (i == winner.TeamID) + continue; + + if (p != null && p.Players != null) + { + 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] as Participant); + } + + public override void OnStop() + { + for (int i = 0; i < m_Controller.TeamInfo.Length; ++i) + m_Controller.TeamInfo[i].Game = null; + + for (int i = 0; i < m_Controller.Hills.Length; ++i) + { + if (m_Controller.Hills[i] != null) + m_Controller.Hills[i].Game = null; + } + + foreach (KHBoard board in m_Controller.Boards) + { + if (board != null) + board.m_Game = null; + } + + for (int i = 0; i < m_Context.Participants.Count; ++i) + ApplyHues(m_Context.Participants[i] as Participant, -1); + + if (m_FinishTimer != null) + m_FinishTimer.Stop(); + m_FinishTimer = null; + } + } +} diff --git a/Scripts/Engines/ConPVP/Tournament.cs b/Scripts/Engines/ConPVP/Tournament.cs index e173c3e5a..9f5ed19d8 100644 --- a/Scripts/Engines/ConPVP/Tournament.cs +++ b/Scripts/Engines/ConPVP/Tournament.cs @@ -9,6 +9,10 @@ using Server.ContextMenus; using Server.Mobiles; using Server.Targeting; using System.Collections.Generic; +using Server.Factions; +using Server.Ethics; +using Server.Ethics.Evil; +using Server.Ethics.Hero; namespace Server.Engines.ConPVP { @@ -80,6 +84,11 @@ namespace Server.Engines.ConPVP return; } + if ( tourny.IsFactionRestricted && Faction.Find( m ) == null ) + { + return; + } + if ( tourny.HasParticipant( m ) ) return; @@ -211,6 +220,17 @@ namespace Server.Engines.ConPVP } } + if ( tourny.IsFactionRestricted && Faction.Find( from ) == null ) + { + if ( m_Registrar != null ) + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, "Only those who have declared their faction allegiance may participate.", from.NetState ); + } + + break; + } + if ( from.HasGump( typeof( AcceptTeamGump ) ) ) { if ( m_Registrar != null ) @@ -398,7 +418,13 @@ namespace Server.Engines.ConPVP } else if ( tourny.TournyType == TournyType.RandomTeam ) { - sb.Append( "Team" ); + sb.Append( tourny.ParticipantsPerMatch ); + sb.Append( "-Team" ); + } + else if ( tourny.TournyType == TournyType.Faction ) + { + sb.Append( tourny.ParticipantsPerMatch ); + sb.Append( "-Team Faction" ); } else if ( tourny.TournyType == TournyType.RedVsBlue ) { @@ -637,6 +663,17 @@ namespace Server.Engines.ConPVP m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); return; } + else if ( tourny.IsFactionRestricted && Faction.Find( mob ) == null ) + { + if ( m_Registrar != null ) + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, "Only those who have declared their faction allegiance may participate.", from.NetState ); + } + + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + return; + } else if ( tourny.HasParticipant( mob ) ) { if ( m_Registrar != null ) @@ -933,6 +970,11 @@ namespace Server.Engines.ConPVP sb.Append( tourny.ParticipantsPerMatch ); sb.Append( "-Team" ); } + else if ( tourny.TournyType == TournyType.Faction ) + { + sb.Append( tourny.ParticipantsPerMatch ); + sb.Append( "-Team Faction" ); + } else if ( tourny.TournyType == TournyType.RedVsBlue ) { sb.Append( "Red v Blue" ); @@ -1326,7 +1368,8 @@ namespace Server.Engines.ConPVP Standard, FreeForAll, RandomTeam, - RedVsBlue + RedVsBlue, + Faction } [PropertyObject] @@ -1335,6 +1378,9 @@ namespace Server.Engines.ConPVP private int m_ParticipantsPerMatch; private int m_PlayersPerParticipant; private int m_LevelRequirement; + + private bool m_FactionRestricted; + private TournyPyramid m_Pyramid; private Ruleset m_Ruleset; @@ -1428,6 +1474,13 @@ namespace Server.Engines.ConPVP set{ m_LevelRequirement = value; } } + [CommandProperty( AccessLevel.GameMaster )] + public bool FactionRestricted + { + get{ return m_FactionRestricted; } + set{ m_FactionRestricted = value; } + } + [CommandProperty( AccessLevel.GameMaster )] public TimeSpan SignupPeriod { @@ -1478,6 +1531,12 @@ namespace Server.Engines.ConPVP set{ m_Undefeated = value; } } + public bool IsFactionRestricted { + get { + return ( m_FactionRestricted || m_TournyType == TournyType.Faction ); + } + } + public bool HasParticipant( Mobile mob ) { for ( int i = 0; i < m_Participants.Count; ++i ) @@ -1493,7 +1552,9 @@ namespace Server.Engines.ConPVP public void Serialize( GenericWriter writer ) { - writer.WriteEncodedInt( (int) 4 ); // version + writer.WriteEncodedInt( (int) 5 ); // version + + writer.Write( (bool) m_FactionRestricted ); writer.Write( (Item) m_EventController ); @@ -1516,6 +1577,11 @@ namespace Server.Engines.ConPVP switch ( version ) { + case 5: { + m_FactionRestricted = reader.ReadBool(); + + goto case 4; + } case 4: { m_EventController = reader.ReadItem() as EventController; @@ -1884,7 +1950,12 @@ namespace Server.Engines.ConPVP else if ( m_TournyType == TournyType.RandomTeam ) { sb.Append( m_ParticipantsPerMatch ); - sb.Append( "-team" ); + sb.Append( "-Team" ); + } + else if ( m_TournyType == TournyType.Faction ) + { + sb.Append( m_ParticipantsPerMatch ); + sb.Append( "-Team Faction" ); } else if ( m_TournyType == TournyType.RedVsBlue ) { @@ -1994,8 +2065,11 @@ namespace Server.Engines.ConPVP } else { - Alert( "Is this all?", "Pitiful. Signup extended." ); - m_SignupStart = DateTime.UtcNow; + /*Alert( "Is this all?", "Pitiful. Signup extended." ); + m_SignupStart = DateTime.UtcNow;*/ + + Alert("Is this all?", "Pitiful. Tournament cancelled."); + m_Stage = TournamentStage.Inactive; } } else if ( Math.Abs( until.TotalSeconds - TimeSpan.FromMinutes( 1.0 ).TotalSeconds ) < (SliceInterval.TotalSeconds/2) ) @@ -2019,6 +2093,42 @@ namespace Server.Engines.ConPVP Alert( "The tournament has completed!", String.Format( "Team {0} has won!", m_EventController.GetTeamName( ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) ) ) ); else if ( m_TournyType == TournyType.RandomTeam ) Alert( "The tournament has completed!", String.Format( "Team {0} has won!", ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) + 1 ) ); + else if ( m_TournyType == TournyType.Faction ) { + if ( m_ParticipantsPerMatch == 4 ) + { + string name = "(null)"; + + switch ( ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) ) + { + case 0: { + name = "Minax"; + break; + } + case 1: { + name = "Council of Mages"; + break; + } + case 2: { + name = "True Britannians"; + break; + } + case 3: { + name = "Shadowlords"; + break; + } + } + + Alert( "The tournament has completed!", String.Format( "The {0} team has won!", name ) ); + } + else if ( m_ParticipantsPerMatch == 2 ) + { + Alert( "The tournament has completed!", String.Format( "The {0} team has won!", ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) == 0 ? "Evil" : "Hero" ) ); + } + else + { + Alert( "The tournament has completed!", String.Format( "Team {0} has won!", ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) + 1 ) ); + } + } else if ( m_TournyType == TournyType.RedVsBlue ) Alert( "The tournament has completed!", String.Format( "Team {0} has won!", ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) == 0 ? "Red" : "Blue" ) ); else @@ -2097,6 +2207,42 @@ namespace Server.Engines.ConPVP Alert( "The tournament has completed!", String.Format( "Team {0} has won", m_EventController.GetTeamName( ( (TournyMatch) ( (PyramidLevel) m_Pyramid.Levels[0] ).Matches[0] ).Participants.IndexOf( winner ) ) ) ); else if ( m_TournyType == TournyType.RandomTeam ) Alert( "The tournament has completed!", String.Format( "Team {0} has won!", ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) + 1 ) ); + else if ( m_TournyType == TournyType.Faction ) { + if ( m_ParticipantsPerMatch == 4 ) + { + string name = "(null)"; + + switch ( ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) ) + { + case 0: { + name = "Minax"; + break; + } + case 1: { + name = "Council of Mages"; + break; + } + case 2: { + name = "True Britannians"; + break; + } + case 3: { + name = "Shadowlords"; + break; + } + } + + Alert( "The tournament has completed!", String.Format( "The {0} team has won!", name ) ); + } + else if ( m_ParticipantsPerMatch == 2 ) + { + Alert( "The tournament has completed!", String.Format( "The {0} team has won!", ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) == 0 ? "Evil" : "Hero" ) ); + } + else + { + Alert( "The tournament has completed!", String.Format( "Team {0} has won!", ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) + 1 ) ); + } + } else if ( m_TournyType == TournyType.RedVsBlue ) Alert( "The tournament has completed!", String.Format( "Team {0} has won!", ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) == 0 ? "Red" : "Blue" ) ); else @@ -2197,6 +2343,56 @@ namespace Server.Engines.ConPVP level.Matches.Add( new TournyMatch( new ArrayList( parts ) ) ); break; } + case TournyType.Faction: + { + TournyParticipant[] parts = new TournyParticipant[partsPerMatch]; + + for ( int i = 0; i < parts.Length; ++i ) + parts[i] = new TournyParticipant( new ArrayList() ); + + for ( int i = 0; i < copy.Count; ++i ) + { + ArrayList players = ((TournyParticipant)copy[i]).Players; + + for ( int j = 0; j < players.Count; ++j ) + { + Mobile mob = (Mobile) players[j]; + + int index = -1; + + if ( partsPerMatch == 4 ) + { + Faction fac = Faction.Find( mob ); + + if ( fac != null ) + { + index = fac.Definition.Sort; + } + } + else if ( partsPerMatch == 2 ) + { + if ( Ethic.Evil.IsEligible( mob ) ) + { + index = 0; + } + else if ( Ethic.Hero.IsEligible( mob ) ) + { + index = 1; + } + } + + if ( index < 0 || index >= partsPerMatch ) + { + index = i % partsPerMatch; + } + + parts[index].Players.Add( mob ); + } + } + + level.Matches.Add( new TournyMatch( new ArrayList( parts ) ) ); + break; + } case TournyType.RandomTeam: { TournyParticipant[] parts = new TournyParticipant[partsPerMatch]; @@ -2693,12 +2889,18 @@ namespace Server.Engines.ConPVP } else if ( tourny.TournyType == TournyType.RandomTeam ) { - sb.Append( "Team" ); + sb.Append( tourny.ParticipantsPerMatch ); + sb.Append( "-Team" ); } else if ( tourny.TournyType == TournyType.RedVsBlue ) { sb.Append( "Red v Blue" ); } + else if ( tourny.TournyType == TournyType.Faction ) + { + sb.Append( tourny.ParticipantsPerMatch ); + sb.Append( "-Team Faction" ); + } else { for ( int i = 0; i < tourny.ParticipantsPerMatch; ++i ) @@ -3063,7 +3265,7 @@ namespace Server.Engines.ConPVP sb.Append( txt ); } } - else if ( m_Tournament.EventController != null || m_Tournament.TournyType == TournyType.RandomTeam || m_Tournament.TournyType == TournyType.RedVsBlue ) + else if ( m_Tournament.EventController != null || m_Tournament.TournyType == TournyType.RandomTeam || m_Tournament.TournyType == TournyType.RedVsBlue || m_Tournament.TournyType == TournyType.Faction ) { for ( int j = 0; j < match.Participants.Count; ++j ) { @@ -3077,6 +3279,42 @@ namespace Server.Engines.ConPVP txt = String.Format( "Team {0} ({1})", m_Tournament.EventController.GetTeamName( j ), part.Players.Count ); else if ( m_Tournament.TournyType == TournyType.RandomTeam ) txt = String.Format( "Team {0} ({1})", j + 1, part.Players.Count ); + else if ( m_Tournament.TournyType == TournyType.Faction ) { + if ( m_Tournament.ParticipantsPerMatch == 4 ) + { + string name = "(null)"; + + switch ( j ) + { + case 0: { + name = "Minax"; + break; + } + case 1: { + name = "Council of Mages"; + break; + } + case 2: { + name = "True Britannians"; + break; + } + case 3: { + name = "Shadowlords"; + break; + } + } + + txt = String.Format( "{0} ({1})", name, part.Players.Count ); + } + else if ( m_Tournament.ParticipantsPerMatch == 2 ) + { + txt = String.Format( "{0} Team ({1})", j==0?"Evil":"Hero", part.Players.Count ); + } + else + { + txt = String.Format( "Team {0} ({1})", j + 1, part.Players.Count ); + } + } else txt = String.Format( "Team {0} ({1})", j == 0 ? "Red" : "Blue", part.Players.Count ); @@ -3131,7 +3369,7 @@ namespace Server.Engines.ConPVP AddRightArrow( 25, 113 + (i * 18), ToButtonID( 6, i ), part.NameList ); } } - else if ( m_Tournament.EventController != null || m_Tournament.TournyType == TournyType.RandomTeam || m_Tournament.TournyType == TournyType.RedVsBlue ) + else if ( m_Tournament.EventController != null || m_Tournament.TournyType == TournyType.RandomTeam || m_Tournament.TournyType == TournyType.RedVsBlue || m_Tournament.TournyType == TournyType.Faction ) { for ( int i = 0; i < match.Participants.Count; ++i ) { @@ -3141,6 +3379,42 @@ namespace Server.Engines.ConPVP AddRightArrow( 25, 113 + (i * 18), ToButtonID( 6, i ), String.Format( "Team {0} ({1})", m_Tournament.EventController.GetTeamName( i ), part.Players.Count ) ); else if ( m_Tournament.TournyType == TournyType.RandomTeam ) AddRightArrow( 25, 113 + (i * 18), ToButtonID( 6, i ), String.Format( "Team {0} ({1})", i+1, part.Players.Count ) ); + else if ( m_Tournament.TournyType == TournyType.Faction ) { + if ( m_Tournament.ParticipantsPerMatch == 4 ) + { + string name = "(null)"; + + switch ( i ) + { + case 0: { + name = "Minax"; + break; + } + case 1: { + name = "Council of Mages"; + break; + } + case 2: { + name = "True Britannians"; + break; + } + case 3: { + name = "Shadowlords"; + break; + } + } + + AddRightArrow( 25, 113 + (i * 18), ToButtonID( 6, i ), String.Format( "{0} ({1})", name, part.Players.Count ) ); + } + else if ( m_Tournament.ParticipantsPerMatch == 2 ) + { + AddRightArrow( 25, 113 + (i * 18), ToButtonID( 6, i ), String.Format( "{0} Team ({1})", i==0?"Evil":"Hero", part.Players.Count ) ); + } + else + { + AddRightArrow( 25, 113 + (i * 18), ToButtonID( 6, i ), String.Format( "Team {0} ({1})", i+1, part.Players.Count ) ); + } + } else AddRightArrow( 25, 113 + (i * 18), ToButtonID( 6, i ), String.Format( "Team {0} ({1})", i==0?"Red":"Blue", part.Players.Count ) ); } diff --git a/Scripts/Scripts.csproj b/Scripts/Scripts.csproj index 9148ed93b..1e53c61f5 100644 --- a/Scripts/Scripts.csproj +++ b/Scripts/Scripts.csproj @@ -181,7 +181,11 @@ + + + +