using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Text; using Server; using Server.Commands; using Server.Engines.PartySystem; using Server.Factions; using Server.Gumps; using Server.Items; using Server.Mobiles; using Server.Network; using Server.Spells; using Server.Spells.Bushido; using Server.Spells.Chivalry; using Server.Spells.Necromancy; using Server.Spells.Ninjitsu; using Server.Spells.Seventh; using Server.Spells.Spellweaving; namespace Server.Engines.ConPVP { public delegate void CountdownCallback( int count ); public class DuelContext { private Mobile m_Initiator; private ArrayList m_Participants; private Ruleset m_Ruleset; private Arena m_Arena; private bool m_Registered = true; private bool m_Finished, m_Started; private bool m_ReadyWait; private int m_ReadyCount; private bool m_Rematch; public bool Rematch{ get{ return m_Rematch; } } public bool ReadyWait{ get{ return m_ReadyWait; } } public int ReadyCount{ get{ return m_ReadyCount; } } public bool Registered{ get{ return m_Registered; } } public bool Finished{ get{ return m_Finished; } } public bool Started{ get{ return m_Started; } } public Mobile Initiator{ get{ return m_Initiator; } } public ArrayList Participants{ get{ return m_Participants; } } public Ruleset Ruleset{ get{ return m_Ruleset; } } public Arena Arena{ get{ return m_Arena; } } private bool CantDoAnything( Mobile mob ) { if ( m_EventGame != null ) return m_EventGame.CantDoAnything( mob ); else return false; } public static bool IsFreeConsume( Mobile mob ) { PlayerMobile pm = mob as PlayerMobile; if ( pm == null || pm.DuelContext == null || pm.DuelContext.m_EventGame == null ) return false; return pm.DuelContext.m_EventGame.FreeConsume; } public void DelayBounce( TimeSpan ts, Mobile mob, Container corpse ) { Timer.DelayCall( ts, new TimerStateCallback( DelayBounce_Callback ), new object[]{ mob, corpse } ); } public static bool AllowSpecialMove( Mobile from, string name, SpecialMove move ) { PlayerMobile pm = from as PlayerMobile; if( pm == null ) return true; DuelContext dc = pm.DuelContext; return (dc == null || dc.InstAllowSpecialMove( from, name, move )); } public bool InstAllowSpecialMove( Mobile from, string name, SpecialMove move ) { if ( !m_StartedBeginCountdown ) return true; DuelPlayer pl = Find( from ); if ( pl == null || pl.Eliminated ) return true; if ( CantDoAnything( from ) ) return false; string title = null; if( move is NinjaMove ) title = "Bushido"; else if( move is SamuraiMove ) title = "Ninjitsu"; if ( title == null || name == null || m_Ruleset.GetOption( title, name ) ) return true; from.SendMessage( "The dueling ruleset prevents you from using this move." ); return false; } public bool AllowSpellCast( Mobile from, Spell spell ) { if ( !m_StartedBeginCountdown ) return true; DuelPlayer pl = Find( from ); if ( pl == null || pl.Eliminated ) return true; if ( CantDoAnything( from ) ) return false; if ( spell is Server.Spells.Fourth.RecallSpell ) from.SendMessage( "You may not cast this spell." ); string title = null, option = null; if( spell is ArcanistSpell ) { title = "Spellweaving"; option = spell.Name; } else if ( spell is PaladinSpell ) { title = "Chivalry"; option = spell.Name; } else if ( spell is NecromancerSpell ) { title = "Necromancy"; option = spell.Name; } else if ( spell is NinjaSpell ) { title = "Ninjitsu"; option = spell.Name; } else if ( spell is SamuraiSpell ) { title = "Bushido"; option = spell.Name; } else if( spell is MagerySpell ) { switch( ((MagerySpell)spell).Circle ) { case SpellCircle.First: title = "1st Circle"; break; case SpellCircle.Second: title = "2nd Circle"; break; case SpellCircle.Third: title = "3rd Circle"; break; case SpellCircle.Fourth: title = "4th Circle"; break; case SpellCircle.Fifth: title = "5th Circle"; break; case SpellCircle.Sixth: title = "6th Circle"; break; case SpellCircle.Seventh: title = "7th Circle"; break; case SpellCircle.Eighth: title = "8th Circle"; break; } option = spell.Name; } else { title = "Other Spell"; option = spell.Name; } if ( title == null || option == null || m_Ruleset.GetOption( title, option ) ) return true; from.SendMessage( "The dueling ruleset prevents you from casting this spell." ); return false; } public bool AllowItemEquip( Mobile from, Item item ) { if ( !m_StartedBeginCountdown ) return true; DuelPlayer pl = Find( from ); if ( pl == null || pl.Eliminated ) return true; if ( item is Dagger || CheckItemEquip( from, item ) ) return true; from.SendMessage( "The dueling ruleset prevents you from equiping this item." ); return false; } public static bool AllowSpecialAbility( Mobile from, string name, bool message ) { PlayerMobile pm = from as PlayerMobile; if ( pm == null ) return true; DuelContext dc = pm.DuelContext; return ( dc == null || dc.InstAllowSpecialAbility( from, name, message ) ); } public bool InstAllowSpecialAbility( Mobile from, string name, bool message ) { if ( !m_StartedBeginCountdown ) return true; DuelPlayer pl = Find( from ); if ( pl == null || pl.Eliminated ) return true; if ( CantDoAnything( from ) ) return false; if ( m_Ruleset.GetOption( "Combat Abilities", name ) ) return true; if ( message ) from.SendMessage( "The dueling ruleset prevents you from using this combat ability." ); return false; } public bool CheckItemEquip( Mobile from, Item item ) { if ( item is Fists ) { if ( !m_Ruleset.GetOption( "Weapons", "Wrestling" ) ) return false; } else if ( item is BaseArmor ) { BaseArmor armor = (BaseArmor)item; if ( armor.ProtectionLevel > ArmorProtectionLevel.Regular && !m_Ruleset.GetOption( "Armor", "Magical" ) ) return false; if ( !Core.AOS && armor.Resource != armor.DefaultResource && !m_Ruleset.GetOption( "Armor", "Colored" ) ) return false; if ( armor is BaseShield && !m_Ruleset.GetOption( "Armor", "Shields" ) ) return false; } else if ( item is BaseWeapon ) { BaseWeapon weapon = (BaseWeapon)item; if ( (weapon.DamageLevel > WeaponDamageLevel.Regular || weapon.AccuracyLevel > WeaponAccuracyLevel.Regular) && !m_Ruleset.GetOption( "Weapons", "Magical" ) ) return false; if ( !Core.AOS && weapon.Resource != CraftResource.Iron && weapon.Resource != CraftResource.None && !m_Ruleset.GetOption( "Weapons", "Runics" ) ) return false; if ( weapon is BaseRanged && !m_Ruleset.GetOption( "Weapons", "Ranged" ) ) return false; if ( !(weapon is BaseRanged) && !m_Ruleset.GetOption( "Weapons", "Melee" ) ) return false; if ( weapon.PoisonCharges > 0 && weapon.Poison != null && !m_Ruleset.GetOption( "Weapons", "Poisoned" ) ) return false; if ( weapon is BaseWand && !m_Ruleset.GetOption( "Items", "Wands" ) ) return false; } return true; } public bool AllowSkillUse( Mobile from, SkillName skill ) { if ( !m_StartedBeginCountdown ) return true; DuelPlayer pl = Find( from ); if ( pl == null || pl.Eliminated ) return true; if ( CantDoAnything( from ) ) return false; int id = (int)skill; if ( id >= 0 && id < SkillInfo.Table.Length ) { if ( m_Ruleset.GetOption( "Skills", SkillInfo.Table[id].Name ) ) return true; } from.SendMessage( "The dueling ruleset prevents you from using this skill." ); return false; } public bool AllowItemUse( Mobile from, Item item ) { if ( !m_StartedBeginCountdown ) return true; DuelPlayer pl = Find( from ); if ( pl == null || pl.Eliminated ) return true; if ( !(item is BaseRefreshPotion) ) { if ( CantDoAnything( from ) ) return false; } string title = null, option = null; if ( item is BasePotion ) { title = "Potions"; if ( item is BaseAgilityPotion ) option = "Agility"; else if ( item is BaseCurePotion ) option = "Cure"; else if ( item is BaseHealPotion ) option = "Heal"; else if ( item is NightSightPotion ) option = "Nightsight"; else if ( item is BasePoisonPotion ) option = "Poison"; else if ( item is BaseStrengthPotion ) option = "Strength"; else if ( item is BaseExplosionPotion ) option = "Explosion"; else if ( item is BaseRefreshPotion ) option = "Refresh"; } else if ( item is Bandage ) { title = "Items"; option = "Bandages"; } else if ( item is TrapableContainer ) { if ( ((TrapableContainer)item).TrapType != TrapType.None ) { title = "Items"; option = "Trapped Containers"; } } else if ( item is Bola ) { title = "Items"; option = "Bolas"; } else if ( item is OrangePetals ) { title = "Items"; option = "Orange Petals"; } else if ( item is EtherealMount || item.Layer == Layer.Mount ) { title = "Items"; option = "Mounts"; } else if ( item is LeatherNinjaBelt ) { title = "Items"; option = "Shurikens"; } else if ( item is Fukiya ) { title = "Items"; option = "Fukiya Darts"; } else if ( item is FireHorn ) { title = "Items"; option = "Fire Horns"; } else if ( item is BaseWand ) { title = "Items"; option = "Wands"; } if ( title != null && option != null && m_StartedBeginCountdown && !m_Started ) { from.SendMessage( "You may not use this item before the duel begins." ); return false; } else if ( item is BasePotion && !(item is BaseExplosionPotion) && !(item is BaseRefreshPotion) && IsSuddenDeath ) { from.SendMessage( 0x22, "You may not drink potions in sudden death." ); return false; } else if ( item is Bandage && IsSuddenDeath ) { from.SendMessage( 0x22, "You may not use bandages in sudden death." ); return false; } if ( title == null || option == null || m_Ruleset.GetOption( title, option ) ) return true; from.SendMessage( "The dueling ruleset prevents you from using this item." ); return false; } private void DelayBounce_Callback( object state ) { object[] states = (object[])state; Mobile mob = (Mobile) states[0]; Container corpse = (Container) states[1]; RemoveAggressions( mob ); SendOutside( mob ); Refresh( mob, corpse ); Debuff( mob ); CancelSpell( mob ); mob.Frozen = false; } public void OnMapChanged( Mobile mob ) { OnLocationChanged( mob ); } public void OnLocationChanged( Mobile mob ) { if ( !m_Registered || !m_StartedBeginCountdown || m_Finished ) return; Arena arena = m_Arena; if ( arena == null ) return; if ( mob.Map == arena.Facet && arena.Bounds.Contains( mob.Location ) ) return; DuelPlayer pl = Find( mob ); if ( pl == null || pl.Eliminated ) return; if ( mob.Map == Map.Internal ) { // they've logged out if ( mob.LogoutMap == arena.Facet && arena.Bounds.Contains( mob.LogoutLocation ) ) { // they logged out inside the arena.. set them to eject on login mob.LogoutLocation = arena.Outside; } } pl.Eliminated = true; mob.LocalOverheadMessage( MessageType.Regular, 0x22, false, "You have forfeited your position in the duel." ); mob.NonlocalOverheadMessage( MessageType.Regular, 0x22, false, String.Format( "{0} has forfeited by leaving the dueling arena.", mob.Name ) ); Participant winner = CheckCompletion(); if ( winner != null ) Finish( winner ); } private bool m_Yielding; public void OnDeath( Mobile mob, Container corpse ) { if ( !m_Registered || !m_Started ) return; DuelPlayer pl = Find( mob ); if ( pl != null && !pl.Eliminated ) { if ( m_EventGame != null && !m_EventGame.OnDeath( mob, corpse ) ) return; pl.Eliminated = true; if ( mob.Poison != null ) mob.Poison = null; Requip( mob, corpse ); DelayBounce( TimeSpan.FromSeconds( 4.0 ), mob, corpse ); Participant winner = CheckCompletion(); if ( winner != null ) { Finish( winner ); } else if ( !m_Yielding ) { mob.LocalOverheadMessage( MessageType.Regular, 0x22, false, "You have been defeated." ); mob.NonlocalOverheadMessage( MessageType.Regular, 0x22, false, String.Format( "{0} has been defeated.", mob.Name ) ); } } } public bool CheckFull() { for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; if ( p.HasOpenSlot ) return false; } return true; } public void Requip( Mobile from, Container cont ) { Corpse corpse = cont as Corpse; if ( corpse == null ) return; List items = new List( corpse.Items ); bool gathered = false; bool didntFit = false; Container pack = from.Backpack; for ( int i = 0; !didntFit && i < items.Count; ++i ) { Item item = items[i]; Point3D loc = item.Location; if ( (item.Layer == Layer.Hair || item.Layer == Layer.FacialHair) || !item.Movable ) continue; if ( pack != null ) { pack.DropItem( item ); gathered = true; } else { didntFit = true; } } corpse.Carved = true; if ( corpse.ItemID == 0x2006 ) { corpse.ProcessDelta(); corpse.SendRemovePacket(); corpse.ItemID = Utility.Random( 0xECA, 9 ); // bone graphic corpse.Hue = 0; corpse.ProcessDelta(); Mobile killer = from.FindMostRecentDamager( false ); if ( killer != null && killer.Player ) killer.AddToBackpack( new Head( m_Tournament == null ? HeadType.Duel : HeadType.Tournament, from.Name ) ); } from.PlaySound( 0x3E3 ); if ( gathered && !didntFit ) from.SendLocalizedMessage( 1062471 ); // You quickly gather all of your belongings. else if ( gathered && didntFit ) from.SendLocalizedMessage( 1062472 ); // You gather some of your belongings. The rest remain on the corpse. } public void Refresh( Mobile mob, Container cont ) { if ( !mob.Alive ) { mob.Resurrect(); DeathRobe robe = mob.FindItemOnLayer( Layer.OuterTorso ) as DeathRobe; if ( robe != null ) robe.Delete(); if ( cont is Corpse ) { Corpse corpse = (Corpse) cont; for ( int i = 0; i < corpse.EquipItems.Count; ++i ) { Item item = corpse.EquipItems[i]; if ( item.Movable && item.Layer != Layer.Hair && item.Layer != Layer.FacialHair && item.IsChildOf( mob.Backpack ) ) mob.EquipItem( item ); } } } mob.Hits = mob.HitsMax; mob.Stam = mob.StamMax; mob.Mana = mob.ManaMax; mob.Poison = null; } public void SendOutside( Mobile mob ) { if ( m_Arena == null ) return; mob.Combatant = null; mob.MoveToWorld( m_Arena.Outside, m_Arena.Facet ); } private Point3D m_GatePoint; private Map m_GateFacet; public void Finish( Participant winner ) { if ( m_Finished ) return; EndAutoTie(); StopSDTimers(); m_Finished = true; for ( int i = 0; i < winner.Players.Length; ++i ) { DuelPlayer pl = winner.Players[i]; if ( pl != null && !pl.Eliminated ) DelayBounce( TimeSpan.FromSeconds( 8.0 ), pl.Mobile, null ); } winner.Broadcast( 0x59, null, winner.Players.Length == 1 ? "{0} has won the duel." : "{0} and {1} team have won the duel.", winner.Players.Length == 1 ? "You have won the duel." : "Your team has won the duel." ); if ( m_Tournament != null && winner.TournyPart != null ) { m_Match.Winner = winner.TournyPart; winner.TournyPart.WonMatch( m_Match ); m_Tournament.HandleWon( m_Arena, m_Match, winner.TournyPart ); } for ( int i = 0; i < m_Participants.Count; ++i ) { Participant loser = (Participant)m_Participants[i]; if ( loser != winner ) { loser.Broadcast( 0x22, null, loser.Players.Length == 1 ? "{0} has lost the duel." : "{0} and {1} team have lost the duel.", loser.Players.Length == 1 ? "You have lost the duel." : "Your team has lost the duel." ); if ( m_Tournament != null && loser.TournyPart != null ) loser.TournyPart.LostMatch( m_Match ); } for ( int j = 0; j < loser.Players.Length; ++j ) { if ( loser.Players[j] != null ) { RemoveAggressions( loser.Players[j].Mobile ); loser.Players[j].Mobile.Delta( MobileDelta.Noto ); loser.Players[j].Mobile.CloseGump( typeof( BeginGump ) ); if ( m_Tournament != null ) loser.Players[j].Mobile.SendEverything(); } } } if ( IsOneVsOne ) { DuelPlayer dp1 = ((Participant)m_Participants[0]).Players[0]; DuelPlayer dp2 = ((Participant)m_Participants[1]).Players[0]; if ( dp1 != null && dp2 != null ) { Award( dp1.Mobile, dp2.Mobile, dp1.Participant == winner ); Award( dp2.Mobile, dp1.Mobile, dp2.Participant == winner ); } } if ( m_EventGame != null ) m_EventGame.OnStop(); Timer.DelayCall( TimeSpan.FromSeconds( 9.0 ), new TimerCallback( UnregisterRematch ) ); } public void Award( Mobile us, Mobile them, bool won ) { Ladder ladder = ( m_Arena == null ? Ladder.Instance : m_Arena.AcquireLadder() ); if ( ladder == null ) return; LadderEntry ourEntry = ladder.Find( us ); LadderEntry theirEntry = ladder.Find( them ); if ( ourEntry == null || theirEntry == null ) return; int xpGain = Ladder.GetExperienceGain( ourEntry, theirEntry, won ); if ( xpGain == 0 ) return; if ( m_Tournament != null ) xpGain *= ( xpGain > 0 ? 5 : 2 ); if ( won ) ++ourEntry.Wins; else ++ourEntry.Losses; int oldLevel = Ladder.GetLevel( ourEntry.Experience ); ourEntry.Experience += xpGain; if ( ourEntry.Experience < 0 ) ourEntry.Experience = 0; ladder.UpdateEntry( ourEntry ); int newLevel = Ladder.GetLevel( ourEntry.Experience ); if ( newLevel > oldLevel ) us.SendMessage( 0x59, "You have achieved level {0}!", newLevel ); else if ( newLevel < oldLevel ) us.SendMessage( 0x22, "You have lost a level. You are now at {0}.", newLevel ); } public void UnregisterRematch() { Unregister(true); } public void Unregister() { Unregister(false); } public void Unregister( bool queryRematch ) { DestroyWall(); if ( !m_Registered ) return; m_Registered = false; if ( m_Arena != null ) m_Arena.Evict(); StopSDTimers(); Type[] types = new Type[]{ typeof( BeginGump ), typeof( DuelContextGump ), typeof( ParticipantGump ), typeof( PickRulesetGump ), typeof( ReadyGump ), typeof( ReadyUpGump ), typeof( RulesetGump ) }; for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer pl = (DuelPlayer)p.Players[j]; if ( pl == null ) continue; if ( pl.Mobile is PlayerMobile ) ((PlayerMobile)pl.Mobile).DuelPlayer = null; for ( int k = 0; k < types.Length; ++k ) pl.Mobile.CloseGump( types[k] ); } } if ( queryRematch && m_Tournament == null ) QueryRematch(); } public void QueryRematch() { DuelContext dc = new DuelContext( m_Initiator, m_Ruleset.Layout, false ); dc.m_Ruleset = m_Ruleset; dc.m_Rematch = true; dc.m_Participants.Clear(); for ( int i = 0; i < m_Participants.Count; ++i ) { Participant oldPart = (Participant)m_Participants[i]; Participant newPart = new Participant( dc, oldPart.Players.Length ); for ( int j = 0; j < oldPart.Players.Length; ++j ) { DuelPlayer oldPlayer = oldPart.Players[j]; if ( oldPlayer != null ) newPart.Players[j] = new DuelPlayer( oldPlayer.Mobile, newPart ); } dc.m_Participants.Add( newPart ); } dc.CloseAllGumps(); dc.SendReadyUpGump(); } public DuelPlayer Find( Mobile mob ) { if ( mob is PlayerMobile ) { PlayerMobile pm = (PlayerMobile)mob; if ( pm.DuelContext == this ) return pm.DuelPlayer; return null; } for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; DuelPlayer pl = p.Find( mob ); if ( pl != null ) return pl; } return null; } public bool IsAlly( Mobile m1, Mobile m2 ) { DuelPlayer pl1 = Find( m1 ); DuelPlayer pl2 = Find( m2 ); return ( pl1 != null && pl2 != null && pl1.Participant == pl2.Participant ); } public Participant CheckCompletion() { Participant winner = null; bool hasWinner = false; int eliminated = 0; for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; if ( p.Eliminated ) { ++eliminated; if ( eliminated == (m_Participants.Count - 1) ) hasWinner = true; } else { winner = p; } } if ( hasWinner ) return winner == null ? (Participant) m_Participants[0] : winner; return null; } private Timer m_Countdown; public void StartCountdown( int count, CountdownCallback cb ) { cb(count); m_Countdown=Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ), count, new TimerStateCallback( Countdown_Callback ), new object[]{ count-1, cb } ); } public void StopCountdown() { if ( m_Countdown != null ) m_Countdown.Stop(); m_Countdown = null; } private void Countdown_Callback( object state ) { object[] states = (object[])state; int count = (int)states[0]; CountdownCallback cb = (CountdownCallback)states[1]; if ( count==0 ) { if ( m_Countdown != null ) m_Countdown.Stop(); m_Countdown=null; } cb( count ); states[0] = count - 1; } private Timer m_AutoTieTimer; private bool m_Tied; public bool Tied{ get{ return m_Tied; } } private bool m_IsSuddenDeath; public bool IsSuddenDeath{ get{ return m_IsSuddenDeath; } set{ m_IsSuddenDeath = value; } } private Timer m_SDWarnTimer, m_SDActivateTimer; public void StopSDTimers() { if ( m_SDWarnTimer != null ) m_SDWarnTimer.Stop(); m_SDWarnTimer = null; if ( m_SDActivateTimer != null ) m_SDActivateTimer.Stop(); m_SDActivateTimer = null; } public void StartSuddenDeath( TimeSpan timeUntilActive ) { if ( m_SDWarnTimer != null ) m_SDWarnTimer.Stop(); m_SDWarnTimer = Timer.DelayCall( TimeSpan.FromMinutes( timeUntilActive.TotalMinutes * 0.9 ), new TimerCallback( WarnSuddenDeath ) ); if ( m_SDActivateTimer != null ) m_SDActivateTimer.Stop(); m_SDActivateTimer = Timer.DelayCall( timeUntilActive, new TimerCallback( ActivateSuddenDeath ) ); } public void WarnSuddenDeath() { for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer pl = p.Players[j]; if ( pl == null || pl.Eliminated ) continue; pl.Mobile.SendSound( 0x1E1 ); pl.Mobile.SendMessage( 0x22, "Warning! Warning! Warning!" ); pl.Mobile.SendMessage( 0x22, "Sudden death will be active soon!" ); } } if ( m_Tournament != null ) m_Tournament.Alert( m_Arena, "Sudden death will be active soon!" ); if ( m_SDWarnTimer != null ) m_SDWarnTimer.Stop(); m_SDWarnTimer = null; } public static bool CheckSuddenDeath( Mobile mob ) { if ( mob is PlayerMobile ) { PlayerMobile pm = (PlayerMobile)mob; if ( pm.DuelPlayer != null && !pm.DuelPlayer.Eliminated && pm.DuelContext != null && pm.DuelContext.IsSuddenDeath ) return true; } return false; } public void ActivateSuddenDeath() { for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer pl = p.Players[j]; if ( pl == null || pl.Eliminated ) continue; pl.Mobile.SendSound( 0x1E1 ); pl.Mobile.SendMessage( 0x22, "Warning! Warning! Warning!" ); pl.Mobile.SendMessage( 0x22, "Sudden death has ACTIVATED. You are now unable to perform any beneficial actions." ); } } if ( m_Tournament != null ) m_Tournament.Alert( m_Arena, "Sudden death has been activated!" ); m_IsSuddenDeath = true; if ( m_SDActivateTimer != null ) m_SDActivateTimer.Stop(); m_SDActivateTimer = null; } public void BeginAutoTie() { if ( m_AutoTieTimer != null ) m_AutoTieTimer.Stop(); TimeSpan ts = ( m_Tournament == null || m_Tournament.TournyType == TournyType.Standard ) ? AutoTieDelay : TimeSpan.FromMinutes( 90.0 ); m_AutoTieTimer = Timer.DelayCall( ts, new TimerCallback( InvokeAutoTie ) ); } public void EndAutoTie() { if ( m_AutoTieTimer != null ) m_AutoTieTimer.Stop(); m_AutoTieTimer = null; } public void InvokeAutoTie() { m_AutoTieTimer = null; if ( !m_Started || m_Finished ) return; m_Tied = true; m_Finished = true; StopSDTimers(); ArrayList remaining = new ArrayList(); for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; if ( p.Eliminated ) { p.Broadcast( 0x22, null, p.Players.Length == 1 ? "{0} has lost the duel." : "{0} and {1} team have lost the duel.", p.Players.Length == 1 ? "You have lost the duel." : "Your team has lost the duel." ); } else { p.Broadcast( 0x59, null, p.Players.Length == 1 ? "{0} has tied the duel due to time expiration." : "{0} and {1} team have tied the duel due to time expiration.", p.Players.Length == 1 ? "You have tied the duel due to time expiration." : "Your team has tied the duel due to time expiration." ); for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer pl = p.Players[j]; if ( pl != null && !pl.Eliminated ) DelayBounce( TimeSpan.FromSeconds( 8.0 ), pl.Mobile, null ); } if ( p.TournyPart != null ) remaining.Add( p.TournyPart ); } for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer pl = p.Players[j]; if ( pl != null ) { pl.Mobile.Delta( MobileDelta.Noto ); pl.Mobile.SendEverything(); } } } if ( m_Tournament != null ) m_Tournament.HandleTie( m_Arena, m_Match, remaining ); Timer.DelayCall( TimeSpan.FromSeconds( 10.0 ), new TimerCallback( Unregister ) ); } public bool IsOneVsOne { get { if ( m_Participants.Count != 2 ) return false; if ( ((Participant)m_Participants[0]).Players.Length != 1 ) return false; if ( ((Participant)m_Participants[1]).Players.Length != 1 ) return false; return true; } } public static void Initialize() { EventSink.Speech += new SpeechEventHandler( EventSink_Speech ); EventSink.Login += new LoginEventHandler( EventSink_Login ); CommandSystem.Register( "vli", AccessLevel.GameMaster, new CommandEventHandler( vli_oc ) ); } private static void vli_oc( CommandEventArgs e ) { e.Mobile.BeginTarget( -1, false, Targeting.TargetFlags.None, new TargetCallback( vli_ot ) ); } private static void vli_ot( Mobile from, object obj ) { if ( obj is PlayerMobile ) { PlayerMobile pm = (PlayerMobile)obj; Ladder ladder = Ladder.Instance; if ( ladder == null ) return; LadderEntry entry = ladder.Find( pm ); if ( entry != null ) from.SendGump( new PropertiesGump( from, entry ) ); } } private static TimeSpan CombatDelay = TimeSpan.FromSeconds( 30.0 ); private static TimeSpan AutoTieDelay = TimeSpan.FromMinutes( 15.0 ); public static bool CheckCombat( Mobile m ) { for ( int i = 0; i < m.Aggressed.Count; ++i ) { AggressorInfo info = m.Aggressed[i]; if ( info.Defender.Player && (DateTime.UtcNow - info.LastCombatTime) < CombatDelay ) return true; } for ( int i = 0; i < m.Aggressors.Count; ++i ) { AggressorInfo info = m.Aggressors[i]; if ( info.Attacker.Player && (DateTime.UtcNow - info.LastCombatTime) < CombatDelay ) return true; } return false; } private static void EventSink_Login( LoginEventArgs e ) { PlayerMobile pm = e.Mobile as PlayerMobile; if ( pm == null ) return; DuelContext dc = pm.DuelContext; if ( dc == null ) return; if ( dc.ReadyWait && pm.DuelPlayer.Ready && !dc.Started && !dc.StartedBeginCountdown && !dc.Finished ) { if ( dc.m_Tournament == null ) pm.SendGump( new ReadyGump( pm, dc, dc.m_ReadyCount ) ); } else if ( dc.ReadyWait && !dc.StartedBeginCountdown && !dc.Started && !dc.Finished ) { if ( dc.m_Tournament == null ) pm.SendGump( new ReadyUpGump( pm, dc ) ); } else if ( dc.Initiator == pm && !dc.ReadyWait && !dc.StartedBeginCountdown && !dc.Started && !dc.Finished ) pm.SendGump( new DuelContextGump( pm, dc ) ); } private static void ViewLadder_OnTarget( Mobile from, object obj, object state ) { if ( obj is PlayerMobile ) { PlayerMobile pm = (PlayerMobile)obj; Ladder ladder = (Ladder)state; LadderEntry entry = ladder.Find( pm ); if ( entry == null ) return; // sanity string text = String.Format( "{{0}} are ranked {0} at level {1}.", LadderGump.Rank( entry.Index + 1 ), Ladder.GetLevel( entry.Experience ) ); pm.PrivateOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( text, from==pm?"You":"They" ), from.NetState ); } else if ( obj is Mobile ) { Mobile mob = (Mobile)obj; if ( mob.Body.IsHuman ) mob.PrivateOverheadMessage( MessageType.Regular, mob.SpeechHue, false, "I'm not a duelist, and quite frankly, I resent the implication.", from.NetState ); else mob.PrivateOverheadMessage( MessageType.Regular, 0x3B2, true, "It's probably better than you.", from.NetState ); } else { from.SendMessage( "That's not a player." ); } } private static void EventSink_Speech( SpeechEventArgs e ) { if ( e.Handled ) return; PlayerMobile pm = e.Mobile as PlayerMobile; if ( pm == null ) return; if ( Insensitive.Contains( e.Speech, "i wish to duel" ) ) { if ( !pm.CheckAlive() ) { } else if ( pm.Region.IsPartOf( typeof( Regions.Jail ) ) ) { } else if ( CheckCombat( pm ) ) { e.Mobile.SendMessage( 0x22, "You have recently been in combat with another player and must wait before starting a duel." ); } else if ( pm.DuelContext != null ) { if ( pm.DuelContext.Initiator == pm ) e.Mobile.SendMessage( 0x22, "You have already started a duel." ); else e.Mobile.SendMessage( 0x22, "You have already been challenged in a duel." ); } else if ( TournamentController.IsActive ) { e.Mobile.SendMessage( 0x22, "You may not start a duel while a tournament is active." ); } else { pm.SendGump( new DuelContextGump( pm, new DuelContext( pm, RulesetLayout.Root ) ) ); e.Handled = true; } } else if ( Insensitive.Equals( e.Speech, "change arena preferences" ) ) { if ( !pm.CheckAlive() ) { } else { Preferences prefs = Preferences.Instance; if ( prefs != null ) { e.Mobile.CloseGump( typeof( PreferencesGump ) ); e.Mobile.SendGump( new PreferencesGump( e.Mobile, prefs ) ); } } } else if ( Insensitive.Equals( e.Speech, "showladder" ) ) { e.Blocked=true; if ( !pm.CheckAlive() ) { } else { Ladder instance = Ladder.Instance; if ( instance == null ) { //pm.SendMessage( "Ladder not yet initialized." ); } else { LadderEntry entry = instance.Find( pm ); if ( entry == null ) return; // sanity string text = String.Format( "{{0}} {{1}} ranked {0} at level {1}.", LadderGump.Rank( entry.Index + 1 ), Ladder.GetLevel( entry.Experience ) ); pm.LocalOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( text, "You", "are" ) ); pm.NonlocalOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( text, pm.Name, "is" ) ); //pm.PublicOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( "Level {0} with {1} win{2} and {3} loss{4}.", Ladder.GetLevel( entry.Experience ), entry.Wins, entry.Wins==1?"":"s", entry.Losses, entry.Losses==1?"":"es" ) ); //pm.PublicOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( "Level {0} with {1} win{2} and {3} loss{4}.", Ladder.GetLevel( entry.Experience ), entry.Wins, entry.Wins==1?"":"s", entry.Losses, entry.Losses==1?"":"es" ) ); } } } else if ( Insensitive.Equals( e.Speech, "viewladder" ) ) { e.Blocked=true; if ( !pm.CheckAlive() ) { } else { Ladder instance = Ladder.Instance; if ( instance == null ) { //pm.SendMessage( "Ladder not yet initialized." ); } else { pm.SendMessage( "Target a player to view their ranking and level." ); pm.BeginTarget( 16, false, Targeting.TargetFlags.None, new TargetStateCallback( ViewLadder_OnTarget ), instance ); } } } else if ( Insensitive.Contains( e.Speech, "i yield" ) ) { if ( !pm.CheckAlive() ) { } else if ( pm.DuelContext == null ) { } else if ( pm.DuelContext.Finished ) { e.Mobile.SendMessage( 0x22, "The duel is already finished." ); } else if ( !pm.DuelContext.Started ) { DuelContext dc = pm.DuelContext; Mobile init = dc.Initiator; if ( pm.DuelContext.StartedBeginCountdown ) { e.Mobile.SendMessage( 0x22, "The duel has not yet started." ); } else { DuelPlayer pl = pm.DuelContext.Find( pm ); if ( pl == null ) return; Participant p = pl.Participant; if ( !pm.DuelContext.ReadyWait ) // still setting stuff up { p.Broadcast( 0x22, null, "{0} has yielded.", "You have yielded." ); if ( init == pm ) { dc.Unregister(); } else { p.Nullify( pl ); pm.DuelPlayer=null; NetState ns = init.NetState; if ( ns != null ) { foreach ( Gump g in ns.Gumps ) { if ( g is ParticipantGump ) { ParticipantGump pg = (ParticipantGump)g; if ( pg.Participant == p ) { init.SendGump( new ParticipantGump( init, dc, p ) ); break; } } else if ( g is DuelContextGump ) { DuelContextGump dcg = (DuelContextGump)g; if ( dcg.Context == dc ) { init.SendGump( new DuelContextGump( init, dc ) ); break; } } } } } } else if ( !pm.DuelContext.StartedReadyCountdown ) // at ready stage { p.Broadcast( 0x22, null, "{0} has yielded.", "You have yielded." ); dc.m_Yielding=true; dc.RejectReady( pm, null ); dc.m_Yielding=false; if ( init == pm ) { dc.Unregister(); } else if ( dc.m_Registered ) { p.Nullify( pl ); pm.DuelPlayer=null; NetState ns = init.NetState; if ( ns != null ) { bool send=true; foreach ( Gump g in ns.Gumps ) { if ( g is ParticipantGump ) { ParticipantGump pg = (ParticipantGump)g; if ( pg.Participant == p ) { init.SendGump( new ParticipantGump( init, dc, p ) ); send=false; break; } } else if ( g is DuelContextGump ) { DuelContextGump dcg = (DuelContextGump)g; if ( dcg.Context == dc ) { init.SendGump( new DuelContextGump( init, dc ) ); send=false; break; } } } if ( send ) init.SendGump( new DuelContextGump( init, dc ) ); } } } else { if ( pm.DuelContext.m_Countdown != null ) pm.DuelContext.m_Countdown.Stop(); pm.DuelContext.m_Countdown= null; pm.DuelContext.m_StartedReadyCountdown=false; p.Broadcast( 0x22, null, "{0} has yielded.", "You have yielded." ); dc.m_Yielding=true; dc.RejectReady( pm, null ); dc.m_Yielding=false; if ( init == pm ) { dc.Unregister(); } else if ( dc.m_Registered ) { p.Nullify( pl ); pm.DuelPlayer=null; NetState ns = init.NetState; if ( ns != null ) { bool send=true; foreach ( Gump g in ns.Gumps ) { if ( g is ParticipantGump ) { ParticipantGump pg = (ParticipantGump)g; if ( pg.Participant == p ) { init.SendGump( new ParticipantGump( init, dc, p ) ); send=false; break; } } else if ( g is DuelContextGump ) { DuelContextGump dcg = (DuelContextGump)g; if ( dcg.Context == dc ) { init.SendGump( new DuelContextGump( init, dc ) ); send=false; break; } } } if ( send ) init.SendGump( new DuelContextGump( init, dc ) ); } } } } } else { DuelPlayer pl = pm.DuelContext.Find( pm ); if ( pl != null ) { if ( pm.DuelContext.IsOneVsOne ) { e.Mobile.SendMessage( 0x22, "You may not yield a 1 on 1 match." ); } else if ( pl.Eliminated ) { e.Mobile.SendMessage( 0x22, "You have already been eliminated." ); } else { pm.LocalOverheadMessage( MessageType.Regular, 0x22, false, "You have yielded." ); pm.NonlocalOverheadMessage( MessageType.Regular, 0x22, false, String.Format( "{0} has yielded.", pm.Name ) ); pm.DuelContext.m_Yielding=true; pm.Kill(); pm.DuelContext.m_Yielding=false; if ( pm.Alive ) // invul, ... { pl.Eliminated = true; pm.DuelContext.RemoveAggressions( pm ); pm.DuelContext.SendOutside( pm ); pm.DuelContext.Refresh( pm, null ); Debuff( pm ); CancelSpell( pm ); pm.Frozen = false; Participant winner = pm.DuelContext.CheckCompletion(); if ( winner != null ) pm.DuelContext.Finish( winner ); } } } else { e.Mobile.SendMessage( 0x22, "BUG: Unable to find duel context." ); } } } } public DuelContext( Mobile initiator, RulesetLayout layout ) : this( initiator, layout, true ) { } public DuelContext( Mobile initiator, RulesetLayout layout, bool addNew ) { m_Initiator = initiator; m_Participants = new ArrayList(); m_Ruleset = new Ruleset( layout ); m_Ruleset.ApplyDefault( layout.Defaults[0] ); if ( addNew ) { m_Participants.Add( new Participant( this, 1 ) ); m_Participants.Add( new Participant( this, 1 ) ); ((Participant)m_Participants[0]).Add( initiator ); } } public void CloseAllGumps() { Type[] types = new Type[]{ typeof( DuelContextGump ), typeof( ParticipantGump ), typeof( RulesetGump ) }; int[] defs = new int[]{ -1, -1, -1 }; for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer pl = p.Players[j]; if ( pl == null ) continue; Mobile mob = pl.Mobile; for ( int k = 0; k < types.Length; ++k ) mob.CloseGump( types[k] ); //mob.CloseGump( types[k], defs[k] ); } } } public void RejectReady( Mobile rejector, string page ) { if ( m_StartedReadyCountdown ) return; // sanity Type[] types = new Type[]{ typeof( DuelContextGump ), typeof( ReadyUpGump ), typeof( ReadyGump ) }; int[] defs = new int[]{ -1, -1, -1 }; for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer pl = p.Players[j]; if ( pl == null ) continue; pl.Ready = false; Mobile mob = pl.Mobile; if ( page == null ) // yield { if ( mob != rejector ) mob.SendMessage( 0x22, "{0} has yielded.", rejector.Name ); } else { if ( mob == rejector ) mob.SendMessage( 0x22, "You have rejected the {0}.", m_Rematch ? "rematch" : page ); else mob.SendMessage( 0x22, "{0} has rejected the {1}.", rejector.Name, m_Rematch ? "rematch" : page ); } for ( int k = 0; k < types.Length; ++k ) mob.CloseGump( types[k] ); //mob.CloseGump( types[k], defs[k] ); } } if ( m_Rematch ) Unregister(); else if ( !m_Yielding ) m_Initiator.SendGump( new DuelContextGump( m_Initiator, this ) ); m_ReadyWait = false; m_ReadyCount = 0; } public void SendReadyGump() { SendReadyGump( -1 ); } public static void Debuff( Mobile mob ) { mob.RemoveStatMod( "[Magic] Str Offset" ); mob.RemoveStatMod( "[Magic] Dex Offset" ); mob.RemoveStatMod( "[Magic] Int Offset" ); mob.RemoveStatMod( "Concussion" ); mob.RemoveStatMod( "blood-rose" ); mob.RemoveStatMod( "clarity-potion" ); OrangePetals.RemoveContext( mob ); mob.Paralyzed = false; mob.Hidden = false; if ( !Core.AOS ) { mob.MagicDamageAbsorb = 0; mob.MeleeDamageAbsorb = 0; Spells.Second.ProtectionSpell.Registry.Remove( mob ); Spells.Fourth.ArchProtectionSpell.RemoveEntry( mob ); mob.EndAction( typeof( DefensiveSpell ) ); } TransformationSpellHelper.RemoveContext( mob, true ); AnimalForm.RemoveContext( mob, true ); if( DisguiseTimers.IsDisguised( mob ) ) DisguiseTimers.StopTimer( mob ); if( !mob.CanBeginAction( typeof( PolymorphSpell ) ) ) { mob.BodyMod = 0; mob.HueMod = -1; mob.EndAction( typeof( PolymorphSpell ) ); } BaseArmor.ValidateMobile( mob ); BaseClothing.ValidateMobile( mob ); mob.Hits = mob.HitsMax; mob.Stam = mob.StamMax; mob.Mana = mob.ManaMax; mob.Poison = null; } public static void CancelSpell( Mobile mob ) { if ( mob.Spell is Spells.Spell ) ((Spells.Spell)mob.Spell).Disturb( Spells.DisturbType.Kill ); Targeting.Target.Cancel( mob ); } private bool m_StartedBeginCountdown; private bool m_StartedReadyCountdown; public bool StartedBeginCountdown{ get{ return m_StartedBeginCountdown; } } public bool StartedReadyCountdown{ get{ return m_StartedReadyCountdown; } } private class InternalWall : Item { public InternalWall() : base( 0x80 ) { Movable = false; } public void Appear( Point3D loc, Map map ) { MoveToWorld( loc, map ); Effects.SendLocationParticles( this, 0x376A, 9, 10, 5025 ); } public InternalWall( 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(); Delete(); } } private ArrayList m_Walls = new ArrayList(); public void DestroyWall() { for ( int i = 0; i < m_Walls.Count; ++i ) ((Item)m_Walls[i]).Delete(); m_Walls.Clear(); } public void CreateWall() { if ( m_Arena == null ) return; Point3D start = m_Arena.Points.EdgeWest; Point3D wall = m_Arena.Wall; int dx = start.X - wall.X; int dy = start.Y - wall.Y; int rx = dx - dy; int ry = dx + dy; bool eastToWest; if ( rx >= 0 && ry >= 0 ) eastToWest = false; else if ( rx >= 0 ) eastToWest = true; else if ( ry >= 0 ) eastToWest = true; else eastToWest = false; Effects.PlaySound( wall, m_Arena.Facet, 0x1F6 ); for ( int i = -1; i <= 1; ++i ) { Point3D loc = new Point3D( eastToWest ? wall.X + i : wall.X, eastToWest ? wall.Y : wall.Y + i, wall.Z ); InternalWall created = new InternalWall(); created.Appear( loc, m_Arena.Facet ); m_Walls.Add( created ); } } public void BuildParties() { for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; if ( p.Players.Length > 1 ) { ArrayList players = new ArrayList(); for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer dp = p.Players[j]; if ( dp == null ) continue; players.Add( dp.Mobile ); } if ( players.Count > 1 ) { for ( int leaderIndex = 0; (leaderIndex+1) < players.Count; leaderIndex += Party.Capacity ) { Mobile leader = (Mobile) players[leaderIndex]; Party party = Party.Get( leader ); if ( party == null ) { leader.Party = party = new Party( leader ); } else if ( party.Leader != leader ) { party.SendPublicMessage( leader, "I leave this party to fight in a duel." ); party.Remove( leader ); leader.Party = party = new Party( leader ); } for ( int j = leaderIndex+1; j < players.Count && j < leaderIndex+Party.Capacity; ++j ) { Mobile player = (Mobile)players[j]; Party existing = Party.Get( player ); if ( existing == party ) continue; if ( (party.Members.Count + party.Candidates.Count) >= Party.Capacity ) { player.SendMessage( "You could not be added to the team party because it is at full capacity." ); leader.SendMessage( "{0} could not be added to the team party because it is at full capacity." ); } else { if ( existing != null ) { existing.SendPublicMessage( player, "I leave this party to fight in a duel." ); existing.Remove( player ); } party.OnAccept( player, true ); } } } } } } } public void ClearIllegalItems() { for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer pl = p.Players[j]; if ( pl == null ) continue; ClearIllegalItems( pl.Mobile ); } } } public void ClearIllegalItems( Mobile mob ) { if ( mob.StunReady && !AllowSpecialAbility( mob, "Stun", false ) ) mob.StunReady = false; if ( mob.DisarmReady && !AllowSpecialAbility( mob, "Disarm", false ) ) mob.DisarmReady = false; Container pack = mob.Backpack; if ( pack == null ) return; for ( int i = mob.Items.Count - 1; i >= 0; --i ) { if ( i >= mob.Items.Count ) continue; // sanity Item item = mob.Items[i]; if ( !CheckItemEquip( mob, item ) ) { pack.DropItem( item ); if ( item is BaseWeapon ) mob.SendLocalizedMessage( 1062001, item.Name == null ? "#" + item.LabelNumber.ToString() : item.Name ); // You can no longer wield your ~1_WEAPON~ else if ( item is BaseArmor && !(item is BaseShield) ) mob.SendLocalizedMessage( 1062002, item.Name == null ? "#" + item.LabelNumber.ToString() : item.Name ); // You can no longer wear your ~1_ARMOR~ else mob.SendLocalizedMessage( 1062003, item.Name == null ? "#" + item.LabelNumber.ToString() : item.Name ); // You can no longer equip your ~1_SHIELD~ } } Item inHand = mob.Holding; if ( inHand != null && !CheckItemEquip( mob, inHand ) ) { mob.Holding = null; BounceInfo bi = inHand.GetBounce(); if ( bi.m_Parent == mob ) pack.DropItem( inHand ); else inHand.Bounce( mob ); inHand.ClearBounce(); } } private void MessageRuleset( Mobile mob ) { if ( m_Ruleset == null ) { return; } Ruleset ruleset = m_Ruleset; Ruleset basedef = ruleset.Base; mob.SendMessage( "Ruleset: {0}", basedef.Title ); BitArray defs; if ( ruleset.Flavors.Count > 0 ) { defs = new BitArray( basedef.Options ); for ( int i = 0; i < ruleset.Flavors.Count; ++i ) { defs.Or( ((Ruleset)ruleset.Flavors[i]).Options ); mob.SendMessage( " + {0}", ((Ruleset)ruleset.Flavors[i]).Title ); } } else { defs = basedef.Options; } int changes = 0; BitArray opts = ruleset.Options; for ( int i = 0; i < opts.Length; ++i ) { if ( defs[i] != opts[i] ) { string name = ruleset.Layout.FindByIndex( i ); if ( name != null ) // sanity { ++changes; if ( changes == 1 ) { mob.SendMessage( "Modifications:" ); } mob.SendMessage( "{0}: {1}", name, opts[i] ? "enabled" : "disabled" ); } } } } public void SendBeginGump( int count ) { if ( !m_Registered || m_Finished ) return; if ( count == 10 ) { CreateWall(); BuildParties(); ClearIllegalItems(); } else if ( count == 0 ) { DestroyWall(); } m_StartedBeginCountdown = true; if ( count == 0 ) { m_Started = true; BeginAutoTie(); } Type[] types = new Type[]{ typeof( ReadyGump ), typeof( ReadyUpGump ), typeof( BeginGump ) }; for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer pl = p.Players[j]; if ( pl == null ) continue; Mobile mob = pl.Mobile; if ( count > 0 ) { if ( count == 10 ) CloseAndSendGump( mob, new BeginGump( count ), types ); mob.Frozen = true; } else { mob.CloseGump( typeof( BeginGump ) ); mob.Frozen = false; } } } } private ArrayList m_Entered = new ArrayList(); private class ReturnEntry { private Mobile m_Mobile; private Point3D m_Location; private Map m_Facet; private DateTime m_Expire; public Mobile Mobile{ get{ return m_Mobile; } } public Point3D Location{ get{ return m_Location; } } public Map Facet{ get{ return m_Facet; } } public void Return() { if ( m_Facet == Map.Internal || m_Facet == null ) return; if ( m_Mobile.Map == Map.Internal ) { m_Mobile.LogoutLocation = m_Location; m_Mobile.LogoutMap = m_Facet; } else { m_Mobile.Location = m_Location; m_Mobile.Map = m_Facet; } } public ReturnEntry( Mobile mob ) { m_Mobile = mob; Update(); } public ReturnEntry( Mobile mob, Point3D loc, Map facet ) { m_Mobile = mob; m_Location = loc; m_Facet = facet; m_Expire = DateTime.UtcNow + TimeSpan.FromMinutes( 30.0 ); } public bool Expired{ get{ return ( DateTime.UtcNow >= m_Expire ); } } public void Update() { m_Expire = DateTime.UtcNow + TimeSpan.FromMinutes( 30.0 ); if ( m_Mobile.Map == Map.Internal ) { m_Facet = m_Mobile.LogoutMap; m_Location = m_Mobile.LogoutLocation; } else { m_Facet = m_Mobile.Map; m_Location = m_Mobile.Location; } } } private class ExitTeleporter : Item { private ArrayList m_Entries; public override string DefaultName { get { return "return teleporter"; } } public ExitTeleporter() : base( 0x1822 ) { m_Entries = new ArrayList(); Hue = 0x482; Movable = false; } public void Register( Mobile mob ) { ReturnEntry entry = Find( mob ); if ( entry != null ) { entry.Update(); return; } m_Entries.Add( new ReturnEntry( mob ) ); } private ReturnEntry Find( Mobile mob ) { for ( int i = 0; i < m_Entries.Count; ++i ) { ReturnEntry entry = (ReturnEntry)m_Entries[i]; if ( entry.Mobile == mob ) return entry; else if ( entry.Expired ) m_Entries.RemoveAt( i-- ); } return null; } public override bool OnMoveOver( Mobile m ) { if ( !base.OnMoveOver( m ) ) return false; ReturnEntry entry = Find( m ); if ( entry != null ) { entry.Return(); Effects.PlaySound( GetWorldLocation(), Map, 0x1FE ); Effects.PlaySound( m.Location, m.Map, 0x1FE ); m_Entries.Remove( entry ); return false; } else { m.SendLocalizedMessage( 1049383 ); // The teleporter doesn't seem to work for you. return true; } } public ExitTeleporter( Serial serial ) : base( serial ) { } public override void Serialize( GenericWriter writer ) { base.Serialize( writer ); writer.Write( (int) 0 ); writer.WriteEncodedInt( (int) m_Entries.Count ); for ( int i = 0; i < m_Entries.Count; ++i ) { ReturnEntry entry = (ReturnEntry)m_Entries[i]; writer.Write( (Mobile) entry.Mobile ); writer.Write( (Point3D) entry.Location ); writer.Write( (Map) entry.Facet ); if ( entry.Expired ) m_Entries.RemoveAt( i-- ); } } public override void Deserialize( GenericReader reader ) { base.Deserialize( reader ); int version = reader.ReadInt(); switch ( version ) { case 0: { int count = reader.ReadEncodedInt(); m_Entries = new ArrayList( count ); for ( int i = 0; i < count; ++i ) { Mobile mob = reader.ReadMobile(); Point3D loc = reader.ReadPoint3D(); Map map = reader.ReadMap(); m_Entries.Add( new ReturnEntry( mob, loc, map ) ); } break; } } } } private class ArenaMoongate : ConfirmationMoongate { private ExitTeleporter m_Teleporter; public override string DefaultName { get { return "spectator moongate"; } } public ArenaMoongate( Point3D target, Map map, ExitTeleporter tp ) : base( target, map ) { m_Teleporter = tp; ItemID = 0x1FD4; Dispellable = false; GumpWidth = 300; GumpHeight = 150; MessageColor = 0xFFC000; MessageString = "Are you sure you wish to spectate this duel?"; TitleColor = 0x7800; TitleNumber = 1062051; // Gate Warning Timer.DelayCall( TimeSpan.FromSeconds( 10.0 ), new TimerCallback( Delete ) ); } public override void CheckGate(Mobile m, int range) { if ( DuelContext.CheckCombat( m ) ) { m.SendMessage( 0x22, "You have recently been in combat with another player and cannot use this moongate." ); } else { base.CheckGate( m, range ); } } public override void UseGate( Mobile m ) { if ( DuelContext.CheckCombat( m ) ) { m.SendMessage( 0x22, "You have recently been in combat with another player and cannot use this moongate." ); } else { if ( m_Teleporter != null && !m_Teleporter.Deleted ) m_Teleporter.Register( m ); base.UseGate( m ); } } public void Appear( Point3D loc, Map map ) { Effects.PlaySound( loc, map, 0x20E ); MoveToWorld( loc, map ); } public ArenaMoongate( 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(); Delete(); } } public void RemoveAggressions( Mobile mob ) { for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer dp = (DuelPlayer)p.Players[j]; if ( dp == null || dp.Mobile == mob ) continue; mob.RemoveAggressed( dp.Mobile ); mob.RemoveAggressor( dp.Mobile ); dp.Mobile.RemoveAggressed( mob ); dp.Mobile.RemoveAggressor( mob ); } } } public void SendReadyUpGump() { if ( !m_Registered ) return; m_ReadyWait = true; m_ReadyCount = -1; Type[] types = new Type[]{ typeof( ReadyUpGump ) }; for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer pl = p.Players[j]; if ( pl == null ) continue; Mobile mob = pl.Mobile; if ( mob != null ) { if ( m_Tournament == null ) CloseAndSendGump( mob, new ReadyUpGump( mob, this ), types ); } } } } public string ValidateStart() { if ( m_Tournament == null && TournamentController.IsActive ) return "a tournament is active"; for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer dp = p.Players[j]; if ( dp == null ) return "a slot is empty"; if ( dp.Mobile.Region.IsPartOf( typeof( Regions.Jail ) ) ) return String.Format( "{0} is in jail", dp.Mobile.Name ); if ( Sigil.ExistsOn( dp.Mobile ) ) return String.Format( "{0} is holding a sigil", dp.Mobile.Name ); if ( !dp.Mobile.Alive ) { if ( m_Tournament == null ) return String.Format( "{0} is dead", dp.Mobile.Name ); else dp.Mobile.Resurrect(); } if ( m_Tournament == null && CheckCombat( dp.Mobile ) ) return String.Format( "{0} is in combat", dp.Mobile.Name ); if ( dp.Mobile.Mounted ) { IMount mount = dp.Mobile.Mount; if ( m_Tournament != null && mount != null ) mount.Rider = null; else return String.Format( "{0} is mounted", dp.Mobile.Name ); } } } return null; } public Arena m_OverrideArena; public Tournament m_Tournament; public TournyMatch m_Match; public EventGame m_EventGame; public Tournament Tournament { get { return m_Tournament; } } public void SendReadyGump( int count ) { if ( !m_Registered ) return; if ( count != -1 ) m_StartedReadyCountdown = true; m_ReadyCount = count; if ( count == 0 ) { string error = ValidateStart(); if ( error != null ) { for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer dp = p.Players[j]; if ( dp != null ) dp.Mobile.SendMessage( "The duel could not be started because {0}.", error ); } } StartCountdown( 10, new CountdownCallback( SendReadyGump ) ); return; } m_ReadyWait = false; List players = new List(); for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer dp = p.Players[j]; if ( dp != null ) players.Add( dp.Mobile ); } } Arena arena = m_OverrideArena; if ( arena == null ) arena = Arena.FindArena( players ); if ( arena == null ) { for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer dp = p.Players[j]; if ( dp != null ) dp.Mobile.SendMessage( "The duel could not be started because there are no arenas. If you want to stop waiting for a free arena, yield the duel." ); } } StartCountdown( 10, new CountdownCallback( SendReadyGump ) ); return; } if ( !arena.IsOccupied ) { m_Arena = arena; if ( m_Initiator.Map == Map.Internal ) { m_GatePoint = m_Initiator.LogoutLocation; m_GateFacet = m_Initiator.LogoutMap; } else { m_GatePoint = m_Initiator.Location; m_GateFacet = m_Initiator.Map; } ExitTeleporter tp = arena.Teleporter as ExitTeleporter; if ( tp == null ) { arena.Teleporter = tp = new ExitTeleporter(); tp.MoveToWorld( arena.GateOut == Point3D.Zero ? arena.Outside : arena.GateOut, arena.Facet ); } ArenaMoongate mg = new ArenaMoongate( arena.GateIn == Point3D.Zero ? arena.Outside : arena.GateIn, arena.Facet, tp ); m_StartedBeginCountdown = true; for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer pl = p.Players[j]; if ( pl == null ) continue; tp.Register( pl.Mobile ); pl.Mobile.Frozen = false; // reset timer just in case pl.Mobile.Frozen = true; Debuff( pl.Mobile ); CancelSpell( pl.Mobile ); pl.Mobile.Delta( MobileDelta.Noto ); } arena.MoveInside( p.Players, i ); } if ( m_EventGame != null ) m_EventGame.OnStart(); StartCountdown( 10, new CountdownCallback( SendBeginGump ) ); mg.Appear( m_GatePoint, m_GateFacet ); } else { for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer dp = p.Players[j]; if ( dp != null ) dp.Mobile.SendMessage( "The duel could not be started because all arenas are full. If you want to stop waiting for a free arena, yield the duel." ); } } StartCountdown( 10, new CountdownCallback( SendReadyGump ) ); } return; } m_ReadyWait = true; bool isAllReady = true; Type[] types = new Type[]{ typeof( ReadyGump ) }; for ( int i = 0; i < m_Participants.Count; ++i ) { Participant p = (Participant)m_Participants[i]; for ( int j = 0; j < p.Players.Length; ++j ) { DuelPlayer pl = p.Players[j]; if ( pl == null ) continue; Mobile mob = pl.Mobile; if ( pl.Ready ) { if ( m_Tournament == null ) CloseAndSendGump( mob, new ReadyGump( mob, this, count ), types ); } else { isAllReady = false; } } } if ( count == -1 && isAllReady ) StartCountdown( 3, new CountdownCallback( SendReadyGump ) ); } public static void CloseAndSendGump( Mobile mob, Gump g, params Type[] types ) { CloseAndSendGump( mob.NetState, g, types ); } public static void CloseAndSendGump( NetState ns, Gump g, params Type[] types ) { if ( ns != null ) { Mobile mob = ns.Mobile; if ( mob != null ) { foreach ( Type type in types ) { mob.CloseGump( type ); } mob.SendGump( g ); } } /*if ( ns == null ) return; for ( int i = 0; i < types.Length; ++i ) ns.Send( new CloseGump( Gump.GetTypeID( types[i] ), 0 ) ); g.SendTo( ns ); ns.AddGump( g ); Packet[] packets = new Packet[types.Length + 1]; for ( int i = 0; i < types.Length; ++i ) packets[i] = new CloseGump( Gump.GetTypeID( types[i] ), 0 ); packets[types.Length] = (Packet) typeof( Gump ).InvokeMember( "Compile", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, g, null, null ); bool compress = ns.CompressionEnabled; ns.CompressionEnabled = false; ns.Send( BindPackets( compress, packets ) ); ns.CompressionEnabled = compress;*/ } /*public static Packet BindPackets( bool compress, params Packet[] packets ) { if ( packets.Length == 0 ) throw new ArgumentException( "No packets to bind", "packets" ); byte[][] compiled = new byte[packets.Length][]; int[] lengths = new int[packets.Length]; int length = 0; for ( int i = 0; i < packets.Length; ++i ) { compiled[i] = packets[i].Compile( compress, out lengths[i] ); length += lengths[i]; } return new BoundPackets( length, compiled, lengths ); } private class BoundPackets : Packet { public BoundPackets( int length, byte[][] compiled, int[] lengths ) : base( 0, length ) { m_Stream.Seek( 0, System.IO.SeekOrigin.Begin ); for ( int i = 0; i < compiled.Length; ++i ) m_Stream.Write( compiled[i], 0, lengths[i] ); } }*/ } }