using System; using System.Net; using System.Collections; using Server; using Server.Mobiles; namespace Server.Factions { public class Election { public static readonly TimeSpan PendingPeriod = TimeSpan.FromDays( 5.0 ); public static readonly TimeSpan CampaignPeriod = TimeSpan.FromDays( 1.0 ); public static readonly TimeSpan VotingPeriod = TimeSpan.FromDays( 3.0 ); public const int MaxCandidates = 10; public const int CandidateRank = 5; private Faction m_Faction; private CandidateCollection m_Candidates; private ElectionState m_State; private DateTime m_LastStateTime; public Faction Faction{ get{ return m_Faction; } } public CandidateCollection Candidates{ get{ return m_Candidates; } } public ElectionState State{ get{ return m_State; } set{ m_State = value; m_LastStateTime = DateTime.Now; } } public DateTime LastStateTime{ get{ return m_LastStateTime; } } [CommandProperty( AccessLevel.GameMaster )] public ElectionState CurrentState{ get{ return m_State; } } [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] public TimeSpan NextStateTime { get { TimeSpan period; switch ( m_State ) { default: case ElectionState.Pending: period = PendingPeriod; break; case ElectionState.Election: period = VotingPeriod; break; case ElectionState.Campaign: period = CampaignPeriod; break; } TimeSpan until = (m_LastStateTime + period) - DateTime.Now; if ( until < TimeSpan.Zero ) until = TimeSpan.Zero; return until; } set { TimeSpan period; switch ( m_State ) { default: case ElectionState.Pending: period = PendingPeriod; break; case ElectionState.Election: period = VotingPeriod; break; case ElectionState.Campaign: period = CampaignPeriod; break; } m_LastStateTime = DateTime.Now - period + value; } } private Timer m_Timer; public void StartTimer() { m_Timer = Timer.DelayCall( TimeSpan.FromMinutes( 1.0 ), TimeSpan.FromMinutes( 1.0 ), new TimerCallback( Slice ) ); } public Election( Faction faction ) { m_Faction = faction; m_Candidates = new CandidateCollection(); StartTimer(); } public Election( GenericReader reader ) { int version = reader.ReadEncodedInt(); switch ( version ) { case 0: { m_Faction = Faction.ReadReference( reader ); m_LastStateTime = reader.ReadDateTime(); m_State = (ElectionState)reader.ReadEncodedInt(); m_Candidates = new CandidateCollection(); int count = reader.ReadEncodedInt(); for ( int i = 0; i < count; ++i ) { Candidate cd = new Candidate( reader ); if ( cd.Mobile != null ) m_Candidates.Add( cd ); } break; } } StartTimer(); } public void Serialize( GenericWriter writer ) { writer.WriteEncodedInt( (int) 0 ); // version Faction.WriteReference( writer, m_Faction ); writer.Write( (DateTime) m_LastStateTime ); writer.WriteEncodedInt( (int) m_State ); writer.WriteEncodedInt( m_Candidates.Count ); for ( int i = 0; i < m_Candidates.Count; ++i ) m_Candidates[i].Serialize( writer ); } public void AddCandidate( Mobile mob ) { if ( IsCandidate( mob ) ) return; m_Candidates.Add( new Candidate( mob ) ); mob.SendLocalizedMessage( 1010117 ); // You are now running for office. } public void RemoveVoter( Mobile mob ) { if ( m_State == ElectionState.Election ) { for ( int i = 0; i < m_Candidates.Count; ++i ) { ArrayList voters = m_Candidates[i].Voters; for ( int j = 0; j < voters.Count; ++j ) { Voter voter = (Voter)voters[j]; if ( voter.From == mob ) voters.RemoveAt( j-- ); } } } } public void RemoveCandidate( Mobile mob ) { Candidate cd = FindCandidate( mob ); if ( cd == null ) return; m_Candidates.Remove( cd ); mob.SendLocalizedMessage( 1038031 ); if ( m_State == ElectionState.Election ) { if ( m_Candidates.Count == 1 ) { m_Faction.Broadcast( 1038031 ); // There are no longer any valid candidates in the Faction Commander election. Candidate winner = m_Candidates[0]; Mobile winMob = winner.Mobile; PlayerState pl = PlayerState.Find( winMob ); if ( pl == null || pl.Faction != m_Faction || winMob == m_Faction.Commander ) { m_Faction.Broadcast( 1038026 ); // Faction leadership has not changed. } else { m_Faction.Broadcast( 1038028 ); // The faction has a new commander. m_Faction.Commander = winMob; } m_Candidates.Clear(); State = ElectionState.Pending; } else if ( m_Candidates.Count == 0 ) // well, I guess this'll never happen { m_Faction.Broadcast( 1038031 ); // There are no longer any valid candidates in the Faction Commander election. m_Candidates.Clear(); State = ElectionState.Pending; } } } public bool IsCandidate( Mobile mob ) { return ( FindCandidate( mob ) != null ); } public bool CanVote( Mobile mob ) { return ( m_State == ElectionState.Election && !HasVoted( mob ) ); } public bool HasVoted( Mobile mob ) { return ( FindVoter( mob ) != null ); } public Candidate FindCandidate( Mobile mob ) { for ( int i = 0; i < m_Candidates.Count; ++i ) { if ( m_Candidates[i].Mobile == mob ) return m_Candidates[i]; } return null; } public Candidate FindVoter( Mobile mob ) { for ( int i = 0; i < m_Candidates.Count; ++i ) { ArrayList voters = m_Candidates[i].Voters; for ( int j = 0; j < voters.Count; ++j ) { Voter voter = (Voter)voters[j]; if ( voter.From == mob ) return m_Candidates[i]; } } return null; } public bool CanBeCandidate( Mobile mob ) { if ( IsCandidate( mob ) ) return false; if ( m_Candidates.Count >= MaxCandidates ) return false; if ( m_State != ElectionState.Campaign ) return false; // sanity.. PlayerState pl = PlayerState.Find( mob ); return ( pl != null && pl.Faction == m_Faction && pl.Rank.Rank >= CandidateRank ); } public void Slice() { if ( m_Faction.Election != this ) { if ( m_Timer != null ) m_Timer.Stop(); m_Timer = null; return; } switch ( m_State ) { case ElectionState.Pending: { if ( (m_LastStateTime + PendingPeriod) > DateTime.Now ) break; m_Faction.Broadcast( 1038023 ); // Campaigning for the Faction Commander election has begun. m_Candidates.Clear(); State = ElectionState.Campaign; break; } case ElectionState.Campaign: { if ( (m_LastStateTime + CampaignPeriod) > DateTime.Now ) break; if ( m_Candidates.Count == 0 ) { m_Faction.Broadcast( 1038025 ); // Nobody ran for office. State = ElectionState.Pending; } else if ( m_Candidates.Count == 1 ) { m_Faction.Broadcast( 1038029 ); // Only one member ran for office. Candidate winner = m_Candidates[0]; Mobile mob = winner.Mobile; PlayerState pl = PlayerState.Find( mob ); if ( pl == null || pl.Faction != m_Faction || mob == m_Faction.Commander ) { m_Faction.Broadcast( 1038026 ); // Faction leadership has not changed. } else { m_Faction.Broadcast( 1038028 ); // The faction has a new commander. m_Faction.Commander = mob; } m_Candidates.Clear(); State = ElectionState.Pending; } else { m_Faction.Broadcast( 1038030 ); State = ElectionState.Election; } break; } case ElectionState.Election: { if ( (m_LastStateTime + VotingPeriod) > DateTime.Now ) break; m_Faction.Broadcast( 1038024 ); // The results for the Faction Commander election are in Candidate winner = null; for ( int i = 0; i < m_Candidates.Count; ++i ) { Candidate cd = m_Candidates[i]; PlayerState pl = PlayerState.Find( cd.Mobile ); if ( pl == null || pl.Faction != m_Faction ) continue; //cd.CleanMuleVotes(); if ( winner == null || cd.Votes > winner.Votes ) winner = cd; } if ( winner == null ) { m_Faction.Broadcast( 1038026 ); // Faction leadership has not changed. } else if ( winner.Mobile == m_Faction.Commander ) { m_Faction.Broadcast( 1038027 ); // The incumbent won the election. } else { m_Faction.Broadcast( 1038028 ); // The faction has a new commander. m_Faction.Commander = winner.Mobile; } m_Candidates.Clear(); State = ElectionState.Pending; break; } } } } public class Voter { private Mobile m_From; private Mobile m_Candidate; private IPAddress m_Address; private DateTime m_Time; public Mobile From { get{ return m_From; } } public Mobile Candidate { get{ return m_Candidate; } } public IPAddress Address { get{ return m_Address; } } public DateTime Time { get{ return m_Time; } } public object[] AcquireFields() { TimeSpan gameTime = TimeSpan.Zero; if ( m_From is PlayerMobile ) gameTime = ((PlayerMobile)m_From).GameTime; int kp = 0; PlayerState pl = PlayerState.Find( m_From ); if ( pl != null ) kp = pl.KillPoints; int sk = m_From.Skills.Total; int factorSkills = 50 + ( (sk * 100 ) / 10000 ); int factorKillPts = 100 + (kp*2); int factorGameTime = 50 + (int) ( (gameTime.Ticks * 100) / TimeSpan.TicksPerDay ); int totalFactor = ( factorSkills * factorKillPts * Math.Max( factorGameTime, 100 ) ) / 10000; if ( totalFactor > 100 ) totalFactor = 100; else if ( totalFactor < 0 ) totalFactor = 0; return new object[]{ m_From, m_Address, m_Time, totalFactor }; } public Voter( Mobile from, Mobile candidate ) { m_From = from; m_Candidate = candidate; if ( m_From.NetState != null ) m_Address = m_From.NetState.Address; else m_Address = IPAddress.None; m_Time = DateTime.Now; } public Voter( GenericReader reader, Mobile candidate ) { m_Candidate = candidate; int version = reader.ReadEncodedInt(); switch ( version ) { case 0: { m_From = reader.ReadMobile(); m_Address = reader.ReadIPAddress(); m_Time = reader.ReadDateTime(); break; } } } public void Serialize( GenericWriter writer ) { writer.WriteEncodedInt( (int) 0 ); writer.Write( (Mobile) m_From ); writer.Write( (IPAddress) m_Address ); writer.Write( (DateTime) m_Time ); } } public class Candidate { private Mobile m_Mobile; private ArrayList m_Voters; public Mobile Mobile{ get{ return m_Mobile; } } public ArrayList Voters{ get{ return m_Voters; } } public int Votes{ get{ return m_Voters.Count; } } public void CleanMuleVotes() { for ( int i = 0; i < m_Voters.Count; ++i ) { Voter voter = (Voter)m_Voters[i]; if ( (int)voter.AcquireFields()[3] < 90 ) m_Voters.RemoveAt( i-- ); } } public Candidate( Mobile mob ) { m_Mobile = mob; m_Voters = new ArrayList(); } public Candidate( GenericReader reader ) { int version = reader.ReadEncodedInt(); switch ( version ) { case 1: { m_Mobile = reader.ReadMobile(); int count = reader.ReadEncodedInt(); m_Voters = new ArrayList( count ); for ( int i = 0; i < count; ++i ) { Voter voter = new Voter( reader, m_Mobile ); if ( voter.From != null ) m_Voters.Add( voter ); } break; } case 0: { m_Mobile = reader.ReadMobile(); ArrayList mobs = reader.ReadMobileList(); m_Voters = new ArrayList( mobs.Count ); for ( int i = 0; i < mobs.Count; ++i ) m_Voters.Add( new Voter( (Mobile)mobs[i], m_Mobile ) ); break; } } } public void Serialize( GenericWriter writer ) { writer.WriteEncodedInt( (int) 1 ); // version writer.Write( (Mobile) m_Mobile ); writer.WriteEncodedInt( (int) m_Voters.Count ); for ( int i = 0; i < m_Voters.Count; ++i ) ((Voter)m_Voters[i]).Serialize( writer ); } } public enum ElectionState { Pending, Campaign, Election } }