Convert movement, actions (lift/use), combat, and spells to use Core.TickCount and avoid DateTime caveats (performance, system time dependency, etc) Refactor DateTime.Now to DateTime.UtcNow Add LOS check for Iron Maiden addon
564 lines
No EOL
13 KiB
C#
564 lines
No EOL
13 KiB
C#
using System;
|
|
using System.Net;
|
|
using System.Collections;
|
|
using Server;
|
|
using Server.Mobiles;
|
|
using System.Collections.Generic;
|
|
|
|
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 List<Candidate> m_Candidates;
|
|
|
|
private ElectionState m_State;
|
|
private DateTime m_LastStateTime;
|
|
|
|
public Faction Faction{ get{ return m_Faction; } }
|
|
|
|
public List<Candidate> Candidates { get { return m_Candidates; } }
|
|
|
|
public ElectionState State{ get{ return m_State; } set{ m_State = value; m_LastStateTime = DateTime.UtcNow; } }
|
|
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.UtcNow;
|
|
|
|
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.UtcNow - 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 List<Candidate>();
|
|
|
|
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 List<Candidate>();
|
|
|
|
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 )
|
|
{
|
|
List<Voter> voters = m_Candidates[i].Voters;
|
|
|
|
for ( int j = 0; j < voters.Count; ++j )
|
|
{
|
|
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 )
|
|
{
|
|
List<Voter> voters = m_Candidates[i].Voters;
|
|
|
|
for ( int j = 0; j < voters.Count; ++j )
|
|
{
|
|
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.UtcNow )
|
|
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.UtcNow )
|
|
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.UtcNow )
|
|
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.UtcNow;
|
|
}
|
|
|
|
public Voter( GenericReader reader, Mobile candidate )
|
|
{
|
|
m_Candidate = candidate;
|
|
|
|
int version = reader.ReadEncodedInt();
|
|
|
|
switch ( version )
|
|
{
|
|
case 0:
|
|
{
|
|
m_From = reader.ReadMobile();
|
|
m_Address = Utility.Intern( 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 List<Voter> m_Voters;
|
|
|
|
public Mobile Mobile{ get{ return m_Mobile; } }
|
|
public List<Voter> 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 List<Voter>();
|
|
}
|
|
|
|
public Candidate( GenericReader reader )
|
|
{
|
|
int version = reader.ReadEncodedInt();
|
|
|
|
switch ( version )
|
|
{
|
|
case 1:
|
|
{
|
|
m_Mobile = reader.ReadMobile();
|
|
|
|
int count = reader.ReadEncodedInt();
|
|
m_Voters = new List<Voter>( 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();
|
|
|
|
List<Mobile> mobs = reader.ReadStrongMobileList();
|
|
m_Voters = new List<Voter>( mobs.Count );
|
|
|
|
for ( int i = 0; i < mobs.Count; ++i )
|
|
m_Voters.Add( new Voter( 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
|
|
}
|
|
} |