Reorganizes Project (#41)

This commit is contained in:
Kamron Batman 2019-08-02 18:13:40 -07:00 committed by GitHub
parent 08bf44af9a
commit 3614a66aee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3499 changed files with 79 additions and 55 deletions

View file

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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,137 @@
using System;
namespace Server.Factions
{
public interface IFactionItem
{
FactionItem FactionItemState{ get; set; }
}
public class FactionItem
{
public static readonly TimeSpan ExpirationPeriod = TimeSpan.FromDays(21.0);
public FactionItem(Item item, Faction faction)
{
Item = item;
Faction = faction;
}
public FactionItem(GenericReader reader, Faction faction)
{
int version = reader.ReadEncodedInt();
switch (version)
{
case 0:
{
Item = reader.ReadItem();
Expiration = reader.ReadDateTime();
break;
}
}
Faction = faction;
}
public Item Item{ get; }
public Faction Faction{ get; }
public DateTime Expiration{ get; private set; }
public bool HasExpired
{
get
{
if (Item?.Deleted != false)
return true;
return Expiration != DateTime.MinValue && DateTime.UtcNow >= Expiration;
}
}
public void StartExpiration()
{
Expiration = DateTime.UtcNow + ExpirationPeriod;
}
public void CheckAttach()
{
if (!HasExpired)
Attach();
else
Detach();
}
public void Attach()
{
if (Item is IFactionItem item)
item.FactionItemState = this;
Faction?.State.FactionItems.Add(this);
}
public void Detach()
{
if (Item is IFactionItem item)
item.FactionItemState = null;
if (Faction?.State.FactionItems.Contains(this) == true)
Faction.State.FactionItems.Remove(this);
}
public void Serialize(GenericWriter writer)
{
writer.WriteEncodedInt(0);
writer.Write(Item);
writer.Write(Expiration);
}
public static int GetMaxWearables(Mobile mob)
{
PlayerState pl = PlayerState.Find(mob);
return pl == null ? 0 : pl.Faction.IsCommander(mob) ? 9 : pl.Rank.MaxWearables;
}
public static FactionItem Find(Item item)
{
if (item is IFactionItem factionItem)
{
FactionItem state = factionItem.FactionItemState;
if (state?.HasExpired == true)
{
state.Detach();
state = null;
}
return state;
}
return null;
}
public static Item Imbue(Item item, Faction faction, bool expire, int hue)
{
if (!(item is IFactionItem))
return item;
FactionItem state = Find(item);
if (state == null)
{
state = new FactionItem(item, faction);
state.Attach();
}
if (expire)
state.StartExpiration();
item.Hue = hue;
return item;
}
}
}

View file

@ -0,0 +1,273 @@
using System;
using System.Collections.Generic;
namespace Server.Factions
{
public class FactionState
{
private const int BroadcastsPerPeriod = 2;
private static readonly TimeSpan BroadcastPeriod = TimeSpan.FromHours(1.0);
private Mobile m_Commander;
private Faction m_Faction;
private DateTime[] m_LastBroadcasts = new DateTime[BroadcastsPerPeriod];
public FactionState(Faction faction)
{
m_Faction = faction;
Tithe = 50;
Members = new List<PlayerState>();
Election = new Election(faction);
FactionItems = new List<FactionItem>();
Traps = new List<BaseFactionTrap>();
}
public FactionState(GenericReader reader)
{
int version = reader.ReadEncodedInt();
switch (version)
{
case 5:
{
LastAtrophy = reader.ReadDateTime();
goto case 4;
}
case 4:
{
int count = reader.ReadEncodedInt();
for (int i = 0; i < count; ++i)
{
DateTime time = reader.ReadDateTime();
if (i < m_LastBroadcasts.Length)
m_LastBroadcasts[i] = time;
}
goto case 3;
}
case 3:
case 2:
case 1:
{
Election = new Election(reader);
goto case 0;
}
case 0:
{
m_Faction = Faction.ReadReference(reader);
m_Commander = reader.ReadMobile();
if (version < 5)
LastAtrophy = DateTime.UtcNow;
if (version < 4)
{
DateTime time = reader.ReadDateTime();
if (m_LastBroadcasts.Length > 0)
m_LastBroadcasts[0] = time;
}
Tithe = reader.ReadEncodedInt();
Silver = reader.ReadEncodedInt();
int memberCount = reader.ReadEncodedInt();
Members = new List<PlayerState>();
for (int i = 0; i < memberCount; ++i)
{
PlayerState pl = new PlayerState(reader, m_Faction, Members);
if (pl.Mobile != null)
Members.Add(pl);
}
m_Faction.State = this;
m_Faction.ZeroRankOffset = Members.Count;
Members.Sort();
for (int i = Members.Count - 1; i >= 0; i--)
{
PlayerState player = Members[i];
if (player.KillPoints <= 0)
m_Faction.ZeroRankOffset = i;
else
player.RankIndex = i;
}
FactionItems = new List<FactionItem>();
if (version >= 2)
{
int factionItemCount = reader.ReadEncodedInt();
for (int i = 0; i < factionItemCount; ++i)
{
FactionItem factionItem = new FactionItem(reader, m_Faction);
Timer.DelayCall(TimeSpan.Zero, factionItem.CheckAttach); // sandbox attachment
}
}
Traps = new List<BaseFactionTrap>();
if (version >= 3)
{
int factionTrapCount = reader.ReadEncodedInt();
for (int i = 0; i < factionTrapCount; ++i)
if (reader.ReadItem() is BaseFactionTrap trap && !trap.CheckDecay())
Traps.Add(trap);
}
break;
}
}
if (version < 1)
Election = new Election(m_Faction);
}
public DateTime LastAtrophy{ get; set; }
public bool FactionMessageReady
{
get
{
for (int i = 0; i < m_LastBroadcasts.Length; ++i)
if (DateTime.UtcNow >= m_LastBroadcasts[i] + BroadcastPeriod)
return true;
return false;
}
}
public bool IsAtrophyReady => DateTime.UtcNow >= LastAtrophy + TimeSpan.FromHours(47.0);
public List<FactionItem> FactionItems{ get; set; }
public List<BaseFactionTrap> Traps{ get; set; }
public Election Election{ get; set; }
public Mobile Commander
{
get => m_Commander;
set
{
m_Commander?.InvalidateProperties();
m_Commander = value;
if (m_Commander != null)
{
m_Commander.SendLocalizedMessage(1042227); // You have been elected Commander of your faction
m_Commander.InvalidateProperties();
PlayerState pl = PlayerState.Find(m_Commander);
if (pl?.Finance != null)
pl.Finance.Finance = null;
if (pl?.Sheriff != null)
pl.Sheriff.Sheriff = null;
}
}
}
public int Tithe{ get; set; }
public int Silver{ get; set; }
public List<PlayerState> Members{ get; set; }
public int CheckAtrophy()
{
if (DateTime.UtcNow < LastAtrophy + TimeSpan.FromHours(47.0))
return 0;
int distrib = 0;
LastAtrophy = DateTime.UtcNow;
List<PlayerState> members = new List<PlayerState>(Members);
for (int i = 0; i < members.Count; ++i)
{
PlayerState ps = members[i];
if (ps.IsActive)
{
ps.IsActive = false;
continue;
}
if (ps.KillPoints > 0)
{
int atrophy = (ps.KillPoints + 9) / 10;
ps.KillPoints -= atrophy;
distrib += atrophy;
}
}
return distrib;
}
public void RegisterBroadcast()
{
for (int i = 0; i < m_LastBroadcasts.Length; ++i)
if (DateTime.UtcNow >= m_LastBroadcasts[i] + BroadcastPeriod)
{
m_LastBroadcasts[i] = DateTime.UtcNow;
break;
}
}
public void Serialize(GenericWriter writer)
{
writer.WriteEncodedInt(5); // version
writer.Write(LastAtrophy);
writer.WriteEncodedInt(m_LastBroadcasts.Length);
for (int i = 0; i < m_LastBroadcasts.Length; ++i)
writer.Write(m_LastBroadcasts[i]);
Election.Serialize(writer);
Faction.WriteReference(writer, m_Faction);
writer.Write(m_Commander);
writer.WriteEncodedInt(Tithe);
writer.WriteEncodedInt(Silver);
writer.WriteEncodedInt(Members.Count);
for (int i = 0; i < Members.Count; ++i)
{
PlayerState pl = Members[i];
pl.Serialize(writer);
}
writer.WriteEncodedInt(FactionItems.Count);
for (int i = 0; i < FactionItems.Count; ++i)
FactionItems[i].Serialize(writer);
writer.WriteEncodedInt(Traps.Count);
for (int i = 0; i < Traps.Count; ++i)
writer.Write(Traps[i]);
}
}
}

View file

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server.Commands;
namespace Server.Factions
{
public class Generator
{
public static void Initialize()
{
CommandSystem.Register("GenerateFactions", AccessLevel.Administrator, GenerateFactions_OnCommand);
}
public static void GenerateFactions_OnCommand(CommandEventArgs e)
{
new FactionPersistance();
List<Faction> factions = Faction.Factions;
foreach (Faction faction in factions)
Generate(faction);
List<Town> towns = Town.Towns;
foreach (Town town in towns)
Generate(town);
}
public static void Generate(Town town)
{
Map facet = Faction.Facet;
TownDefinition def = town.Definition;
if (!CheckExistance(def.Monolith, facet, typeof(TownMonolith)))
{
TownMonolith mono = new TownMonolith(town);
mono.MoveToWorld(def.Monolith, facet);
mono.Sigil = new Sigil(town);
}
if (!CheckExistance(def.TownStone, facet, typeof(TownStone)))
new TownStone(town).MoveToWorld(def.TownStone, facet);
}
public static void Generate(Faction faction)
{
Map facet = Faction.Facet;
List<Town> towns = Town.Towns;
StrongholdDefinition stronghold = faction.Definition.Stronghold;
if (!CheckExistance(stronghold.JoinStone, facet, typeof(JoinStone)))
new JoinStone(faction).MoveToWorld(stronghold.JoinStone, facet);
if (!CheckExistance(stronghold.FactionStone, facet, typeof(FactionStone)))
new FactionStone(faction).MoveToWorld(stronghold.FactionStone, facet);
for (int i = 0; i < stronghold.Monoliths.Length; ++i)
{
Point3D monolith = stronghold.Monoliths[i];
if (!CheckExistance(monolith, facet, typeof(StrongholdMonolith)))
new StrongholdMonolith(towns[i], faction).MoveToWorld(monolith, facet);
}
}
private static bool CheckExistance(Point3D loc, Map facet, Type type)
{
return facet.GetItemsInRange(loc, 0).Any(type.IsInstanceOfType);
}
}
}

View file

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
namespace Server.Factions
{
public class GuardList
{
public GuardList(GuardDefinition definition)
{
Definition = definition;
Guards = new List<BaseFactionGuard>();
}
public GuardDefinition Definition{ get; }
public List<BaseFactionGuard> Guards{ get; }
public BaseFactionGuard Construct()
{
try
{
return Activator.CreateInstance(Definition.Type) as BaseFactionGuard;
}
catch
{
return null;
}
}
}
}

View file

@ -0,0 +1,154 @@
using System;
using Server.Mobiles;
using Server.Network;
namespace Server.Factions
{
public class Keywords
{
public static void Initialize()
{
EventSink.Speech += EventSink_Speech;
}
private static void ShowScore_Sandbox(PlayerState pl)
{
pl?.Mobile.PublicOverheadMessage(MessageType.Regular, pl.Mobile.SpeechHue, true,
pl.KillPoints.ToString("N0")); // NOTE: Added 'N0'
}
private static void EventSink_Speech(SpeechEventArgs e)
{
Mobile from = e.Mobile;
int[] keywords = e.Keywords;
for (int i = 0; i < keywords.Length; ++i)
switch (keywords[i])
{
case 0x00E4: // *i wish to access the city treasury*
{
Town town = Town.FromRegion(from.Region);
if (town == null || !town.IsFinance(from) || !from.Alive)
break;
if (FactionGump.Exists(from))
from.SendLocalizedMessage(1042160); // You already have a faction menu open.
else if (town.Owner != null && from is PlayerMobile mobile)
mobile.SendGump(new FinanceGump(mobile, town.Owner, town));
break;
}
case 0x0ED: // *i am sheriff*
{
Town town = Town.FromRegion(from.Region);
if (town == null || !town.IsSheriff(from) || !from.Alive)
break;
if (FactionGump.Exists(from))
from.SendLocalizedMessage(1042160); // You already have a faction menu open.
else if (town.Owner != null)
from.SendGump(new SheriffGump((PlayerMobile)from, town.Owner, town));
break;
}
case 0x00EF: // *you are fired*
{
Town town = Town.FromRegion(from.Region);
if (town == null)
break;
if (town.IsFinance(from) || town.IsSheriff(from))
town.BeginOrderFiring(from);
break;
}
case 0x00E5: // *i wish to resign as finance minister*
{
PlayerState pl = PlayerState.Find(from);
if (pl?.Finance != null)
{
pl.Finance.Finance = null;
from.SendLocalizedMessage(1005081); // You have been fired as Finance Minister
}
break;
}
case 0x00EE: // *i wish to resign as sheriff*
{
PlayerState pl = PlayerState.Find(from);
if (pl?.Sheriff != null)
{
pl.Sheriff.Sheriff = null;
from.SendLocalizedMessage(1010270); // You have been fired as Sheriff
}
break;
}
case 0x00E9: // *what is my faction term status*
{
PlayerState pl = PlayerState.Find(from);
if (pl?.IsLeaving == true)
{
if (Faction.CheckLeaveTimer(from))
break;
TimeSpan remaining = pl.Leaving + Faction.LeavePeriod - DateTime.UtcNow;
if (remaining.TotalDays >= 1)
from.SendLocalizedMessage(1042743,
remaining.TotalDays
.ToString("N0")); // Your term of service will come to an end in ~1_DAYS~ days.
else if (remaining.TotalHours >= 1)
from.SendLocalizedMessage(1042741,
remaining.TotalHours
.ToString("N0")); // Your term of service will come to an end in ~1_HOURS~ hours.
else
from.SendLocalizedMessage(
1042742); // Your term of service will come to an end in less than one hour.
}
else if (pl != null)
{
from.SendLocalizedMessage(1042233); // You are not in the process of quitting the faction.
}
break;
}
case 0x00EA: // *message faction*
{
Faction faction = Faction.Find(from);
if (faction == null || !faction.IsCommander(from))
break;
if (from.AccessLevel == AccessLevel.Player && !faction.FactionMessageReady)
from.SendLocalizedMessage(
1010264); // The required time has not yet passed since the last message was sent
else
faction.BeginBroadcast(from);
break;
}
case 0x00EC: // *showscore*
{
PlayerState pl = PlayerState.Find(from);
if (pl != null)
Timer.DelayCall(TimeSpan.Zero, ShowScore_Sandbox, pl);
break;
}
case 0x0178: // i honor your leadership
{
Faction.Find(from)?.BeginHonorLeadership(from);
break;
}
}
}
}
}

View file

@ -0,0 +1,92 @@
namespace Server.Factions
{
public enum MerchantTitle
{
None,
Scribe,
Carpenter,
Blacksmith,
Bowyer,
Tialor
}
public class MerchantTitleInfo
{
public MerchantTitleInfo(SkillName skill, double requirement, TextDefinition title, TextDefinition label,
TextDefinition assigned)
{
Skill = skill;
Requirement = requirement;
Title = title;
Label = label;
Assigned = assigned;
}
public SkillName Skill{ get; }
public double Requirement{ get; }
public TextDefinition Title{ get; }
public TextDefinition Label{ get; }
public TextDefinition Assigned{ get; }
}
public class MerchantTitles
{
public static MerchantTitleInfo[] Info{ get; } =
{
new MerchantTitleInfo(SkillName.Inscribe, 90.0, new TextDefinition(1060773, "Scribe"),
new TextDefinition(1011468, "SCRIBE"),
new TextDefinition(1010121, "You now have the faction title of scribe")),
new MerchantTitleInfo(SkillName.Carpentry, 90.0, new TextDefinition(1060774, "Carpenter"),
new TextDefinition(1011469, "CARPENTER"),
new TextDefinition(1010122, "You now have the faction title of carpenter")),
new MerchantTitleInfo(SkillName.Tinkering, 90.0, new TextDefinition(1022984, "Tinker"),
new TextDefinition(1011470, "TINKER"),
new TextDefinition(1010123, "You now have the faction title of tinker")),
new MerchantTitleInfo(SkillName.Blacksmith, 90.0, new TextDefinition(1023016, "Blacksmith"),
new TextDefinition(1011471, "BLACKSMITH"),
new TextDefinition(1010124, "You now have the faction title of blacksmith")),
new MerchantTitleInfo(SkillName.Fletching, 90.0, new TextDefinition(1023022, "Bowyer"),
new TextDefinition(1011472, "BOWYER"),
new TextDefinition(1010125, "You now have the faction title of Bowyer")),
new MerchantTitleInfo(SkillName.Tailoring, 90.0, new TextDefinition(1022982, "Tailor"),
new TextDefinition(1018300, "TAILOR"),
new TextDefinition(1042162, "You now have the faction title of Tailor"))
};
public static MerchantTitleInfo GetInfo(MerchantTitle title)
{
int idx = (int)title - 1;
if (idx >= 0 && idx < Info.Length)
return Info[idx];
return null;
}
public static bool HasMerchantQualifications(Mobile mob)
{
for (int i = 0; i < Info.Length; ++i)
if (IsQualified(mob, Info[i]))
return true;
return false;
}
public static bool IsQualified(Mobile mob, MerchantTitle title)
{
return IsQualified(mob, GetInfo(title));
}
public static bool IsQualified(Mobile mob, MerchantTitleInfo info)
{
if (mob == null || info == null)
return false;
return mob.Skills[info.Skill].Value >= info.Requirement;
}
}
}

View file

@ -0,0 +1,90 @@
using System.Collections.Generic;
namespace Server.Factions
{
public class FactionPersistance : Item
{
public FactionPersistance() : base(1)
{
Movable = false;
if (Instance?.Deleted == true)
Instance = this;
else
base.Delete();
}
public FactionPersistance(Serial serial) : base(serial)
{
Instance = this;
}
public static FactionPersistance Instance{ get; private set; }
public override string DefaultName => "Faction Persistance - Internal";
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
List<Faction> factions = Faction.Factions;
for (int i = 0; i < factions.Count; ++i)
{
writer.WriteEncodedInt((int)PersistedType.Faction);
factions[i].State.Serialize(writer);
}
List<Town> towns = Town.Towns;
for (int i = 0; i < towns.Count; ++i)
{
writer.WriteEncodedInt((int)PersistedType.Town);
towns[i].State.Serialize(writer);
}
writer.WriteEncodedInt((int)PersistedType.Terminator);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 0:
{
PersistedType type;
while ((type = (PersistedType)reader.ReadEncodedInt()) != PersistedType.Terminator)
switch (type)
{
case PersistedType.Faction:
new FactionState(reader);
break;
case PersistedType.Town:
new TownState(reader);
break;
}
break;
}
}
}
public override void Delete()
{
}
private enum PersistedType
{
Terminator,
Faction,
Town
}
}
}

View file

@ -0,0 +1,303 @@
using System;
using System.Collections.Generic;
using Server.Mobiles;
namespace Server.Factions
{
public class PlayerState : IComparable<PlayerState>
{
private Town m_Finance;
private bool m_InvalidateRank = true;
private int m_KillPoints;
private MerchantTitle m_MerchantTitle;
private RankDefinition m_Rank;
private int m_RankIndex = -1;
private Town m_Sheriff;
public PlayerState(Mobile mob, Faction faction, List<PlayerState> owner)
{
Mobile = mob;
Faction = faction;
Owner = owner;
Attach();
Invalidate();
}
public PlayerState(GenericReader reader, Faction faction, List<PlayerState> owner)
{
Faction = faction;
Owner = owner;
int version = reader.ReadEncodedInt();
switch (version)
{
case 1:
{
IsActive = reader.ReadBool();
LastHonorTime = reader.ReadDateTime();
goto case 0;
}
case 0:
{
Mobile = reader.ReadMobile();
m_KillPoints = reader.ReadEncodedInt();
m_MerchantTitle = (MerchantTitle)reader.ReadEncodedInt();
Leaving = reader.ReadDateTime();
break;
}
}
Attach();
}
public Mobile Mobile{ get; }
public Faction Faction{ get; }
public List<PlayerState> Owner{ get; }
public MerchantTitle MerchantTitle
{
get => m_MerchantTitle;
set
{
m_MerchantTitle = value;
Invalidate();
}
}
public Town Sheriff
{
get => m_Sheriff;
set
{
m_Sheriff = value;
Invalidate();
}
}
public Town Finance
{
get => m_Finance;
set
{
m_Finance = value;
Invalidate();
}
}
public List<SilverGivenEntry> SilverGiven{ get; private set; }
public int KillPoints
{
get => m_KillPoints;
set
{
if (m_KillPoints != value)
{
if (value > m_KillPoints)
{
if (m_KillPoints <= 0)
{
if (value <= 0)
{
m_KillPoints = value;
Invalidate();
return;
}
Owner.Remove(this);
Owner.Insert(Faction.ZeroRankOffset, this);
m_RankIndex = Faction.ZeroRankOffset;
Faction.ZeroRankOffset++;
}
while (m_RankIndex - 1 >= 0)
{
PlayerState p = Owner[m_RankIndex - 1];
if (value > p.KillPoints)
{
Owner[m_RankIndex] = p;
Owner[m_RankIndex - 1] = this;
RankIndex--;
p.RankIndex++;
}
else
{
break;
}
}
}
else
{
if (value <= 0)
{
if (m_KillPoints <= 0)
{
m_KillPoints = value;
Invalidate();
return;
}
while (m_RankIndex + 1 < Faction.ZeroRankOffset)
{
PlayerState p = Owner[m_RankIndex + 1];
Owner[m_RankIndex + 1] = this;
Owner[m_RankIndex] = p;
RankIndex++;
p.RankIndex--;
}
m_RankIndex = -1;
Faction.ZeroRankOffset--;
}
else
{
while (m_RankIndex + 1 < Faction.ZeroRankOffset)
{
PlayerState p = Owner[m_RankIndex + 1];
if (value < p.KillPoints)
{
Owner[m_RankIndex + 1] = this;
Owner[m_RankIndex] = p;
RankIndex++;
p.RankIndex--;
}
else
{
break;
}
}
}
}
m_KillPoints = value;
Invalidate();
}
}
}
public int RankIndex
{
get => m_RankIndex;
set
{
if (m_RankIndex != value)
{
m_RankIndex = value;
m_InvalidateRank = true;
}
}
}
public RankDefinition Rank
{
get
{
if (m_InvalidateRank)
{
RankDefinition[] ranks = Faction.Definition.Ranks;
int percent;
if (Owner.Count == 1)
percent = 1000;
else if (m_RankIndex == -1)
percent = 0;
else
percent = (Faction.ZeroRankOffset - m_RankIndex) * 1000 / Faction.ZeroRankOffset;
for (int i = 0; i < ranks.Length; i++)
{
RankDefinition check = ranks[i];
if (percent >= check.Required)
{
m_Rank = check;
m_InvalidateRank = false;
break;
}
}
Invalidate();
}
return m_Rank;
}
}
public DateTime LastHonorTime{ get; set; }
public DateTime Leaving{ get; set; }
public bool IsLeaving => Leaving > DateTime.MinValue;
public bool IsActive{ get; set; }
public int CompareTo(PlayerState ps)
{
return (ps?.m_KillPoints ?? 0) - m_KillPoints;
}
public bool CanGiveSilverTo(Mobile mob)
{
for (int i = 0; i < SilverGiven?.Count; ++i)
{
SilverGivenEntry sge = SilverGiven[i];
if (sge.IsExpired)
SilverGiven.RemoveAt(i--);
else if (sge.GivenTo == mob)
return false;
}
return true;
}
public void OnGivenSilverTo(Mobile mob)
{
if (SilverGiven == null)
SilverGiven = new List<SilverGivenEntry>();
SilverGiven.Add(new SilverGivenEntry(mob));
}
public void Invalidate()
{
(Mobile as PlayerMobile)?.InvalidateProperties();
}
public void Attach()
{
if (Mobile is PlayerMobile mobile)
mobile.FactionPlayerState = this;
}
public void Serialize(GenericWriter writer)
{
writer.WriteEncodedInt(1); // version
writer.Write(IsActive);
writer.Write(LastHonorTime);
writer.Write(Mobile);
writer.WriteEncodedInt(m_KillPoints);
writer.WriteEncodedInt((int)m_MerchantTitle);
writer.Write(Leaving);
}
public static PlayerState Find(Mobile mob)
{
return mob is PlayerMobile mobile ? mobile.FactionPlayerState : null;
}
}
}

View file

@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Server.Factions
{
public class Reflector
{
private static List<Town> m_Towns;
private static List<Faction> m_Factions;
public static List<Town> Towns
{
get
{
if (m_Towns == null)
ProcessTypes();
return m_Towns;
}
}
public static List<Faction> Factions
{
get
{
if (m_Factions == null)
ProcessTypes();
return m_Factions;
}
}
private static object Construct(Type type)
{
try
{
return Activator.CreateInstance(type);
}
catch
{
return null;
}
}
private static void ProcessTypes()
{
m_Factions = new List<Faction>();
m_Towns = new List<Town>();
Assembly[] asms = ScriptCompiler.Assemblies;
for (int i = 0; i < asms.Length; ++i)
{
Assembly asm = asms[i];
TypeCache tc = ScriptCompiler.GetTypeCache(asm);
Type[] types = tc.Types;
for (int j = 0; j < types.Length; ++j)
{
Type type = types[j];
if (type.IsSubclassOf(typeof(Faction)))
{
if (Construct(type) is Faction faction)
Faction.Factions.Add(faction);
}
else if (type.IsSubclassOf(typeof(Town)))
{
if (Construct(type) is Town town)
Town.Towns.Add(town);
}
}
}
}
}
}

View file

@ -0,0 +1,21 @@
using System;
namespace Server.Factions
{
public class SilverGivenEntry
{
public static readonly TimeSpan ExpirePeriod = TimeSpan.FromHours(3.0);
public SilverGivenEntry(Mobile givenTo)
{
GivenTo = givenTo;
TimeOfGift = DateTime.UtcNow;
}
public Mobile GivenTo{ get; }
public DateTime TimeOfGift{ get; }
public bool IsExpired => TimeOfGift + ExpirePeriod < DateTime.UtcNow;
}
}

View file

@ -0,0 +1,40 @@
using Server.Mobiles;
using Server.Regions;
namespace Server.Factions
{
public class StrongholdRegion : BaseRegion
{
public StrongholdRegion(Faction faction) : base(faction.Definition.FriendlyName, Faction.Facet, DefaultPriority,
faction.Definition.Stronghold.Area)
{
Faction = faction;
Register();
}
public Faction Faction{ get; set; }
public override bool OnMoveInto(Mobile m, Direction d, Point3D newLocation, Point3D oldLocation)
{
if (!base.OnMoveInto(m, d, newLocation, oldLocation))
return false;
if (m.AccessLevel >= AccessLevel.Counselor || Contains(oldLocation))
return true;
if (m is PlayerMobile pm && pm.DuelContext != null)
{
pm.SendMessage("You may not enter this area while participating in a duel or a tournament.");
return false;
}
return Faction.Find(m, true, true) != null;
}
public override bool AllowHousing(Mobile from, Point3D p)
{
return false;
}
}
}

View file

@ -0,0 +1,505 @@
using System;
using System.Collections.Generic;
using Server.Commands;
using Server.Targeting;
namespace Server.Factions
{
[CustomEnum(new[] { "Britain", "Magincia", "Minoc", "Moonglow", "Skara Brae", "Trinsic", "Vesper", "Yew" })]
public abstract class Town : IComparable<Town>
{
public const int SilverCaptureBonus = 10000;
public static readonly TimeSpan TaxChangePeriod = TimeSpan.FromHours(12.0);
public static readonly TimeSpan IncomePeriod = TimeSpan.FromDays(1.0);
private Timer m_IncomeTimer;
private TownState m_State;
public Town()
{
m_State = new TownState(this);
ConstructVendorLists();
ConstructGuardLists();
StartIncomeTimer();
}
public TownDefinition Definition{ get; set; }
public TownState State
{
get => m_State;
set
{
m_State = value;
ConstructGuardLists();
}
}
public int Silver
{
get => m_State.Silver;
set => m_State.Silver = value;
}
public Faction Owner
{
get => m_State.Owner;
set => Capture(value);
}
public Mobile Sheriff
{
get => m_State.Sheriff;
set => m_State.Sheriff = value;
}
public Mobile Finance
{
get => m_State.Finance;
set => m_State.Finance = value;
}
public int Tax
{
get => m_State.Tax;
set => m_State.Tax = value;
}
public DateTime LastTaxChange
{
get => m_State.LastTaxChange;
set => m_State.LastTaxChange = value;
}
public bool TaxChangeReady => m_State.LastTaxChange + TaxChangePeriod < DateTime.UtcNow;
public int FinanceUpkeep
{
get
{
List<VendorList> vendorLists = VendorLists;
int upkeep = 0;
for (int i = 0; i < vendorLists.Count; ++i)
upkeep += vendorLists[i].Vendors.Count * vendorLists[i].Definition.Upkeep;
return upkeep;
}
}
public int SheriffUpkeep
{
get
{
List<GuardList> guardLists = GuardLists;
int upkeep = 0;
for (int i = 0; i < guardLists.Count; ++i)
upkeep += guardLists[i].Guards.Count * guardLists[i].Definition.Upkeep;
return upkeep;
}
}
public int DailyIncome => 10000 * (100 + m_State.Tax) / 100;
public int NetCashFlow => DailyIncome - FinanceUpkeep - SheriffUpkeep;
public TownMonolith Monolith
{
get
{
List<BaseMonolith> monoliths = BaseMonolith.Monoliths;
foreach (BaseMonolith monolith in monoliths)
if (monolith is TownMonolith townMonolith && townMonolith.Town == this)
return townMonolith;
return null;
}
}
public DateTime LastIncome
{
get => m_State.LastIncome;
set => m_State.LastIncome = value;
}
public List<VendorList> VendorLists{ get; set; }
public List<GuardList> GuardLists{ get; set; }
public static List<Town> Towns => Reflector.Towns;
public int CompareTo(Town other)
{
return Definition.Sort - (other?.Definition.Sort ?? 0);
}
public static Town FromRegion(Region reg)
{
if (reg.Map != Faction.Facet)
return null;
List<Town> towns = Towns;
for (int i = 0; i < towns.Count; ++i)
{
Town town = towns[i];
if (reg.IsPartOf(town.Definition.Region))
return town;
}
return null;
}
public void BeginOrderFiring(Mobile from)
{
bool isFinance = IsFinance(from);
bool isSheriff = IsSheriff(from);
string type = null;
// NOTE: Messages not OSI-accurate, intentional
if (isFinance && isSheriff) // GM only
type = "vendor or guard";
else if (isFinance)
type = "vendor";
else if (isSheriff)
type = "guard";
from.SendMessage("Target the {0} you wish to dismiss.", type);
from.BeginTarget(12, false, TargetFlags.None, EndOrderFiring);
}
public void EndOrderFiring(Mobile from, object obj)
{
bool isFinance = IsFinance(from);
bool isSheriff = IsSheriff(from);
string type = null;
if (isFinance && isSheriff) // GM only
type = "vendor or guard";
else if (isFinance)
type = "vendor";
else if (isSheriff)
type = "guard";
if (obj is BaseFactionVendor vendor && vendor.Town == this && isFinance)
vendor.Delete();
else if (obj is BaseFactionGuard guard && guard.Town == this && isSheriff)
guard.Delete();
else
from.SendMessage("That is not a {0}!", type);
}
public void StartIncomeTimer()
{
m_IncomeTimer?.Stop();
m_IncomeTimer = Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), CheckIncome);
}
public void StopIncomeTimer()
{
m_IncomeTimer?.Stop();
m_IncomeTimer = null;
}
public void CheckIncome()
{
if (LastIncome + IncomePeriod > DateTime.UtcNow || Owner == null)
return;
ProcessIncome();
}
public void ProcessIncome()
{
LastIncome = DateTime.UtcNow;
int flow = NetCashFlow;
if (Silver + flow < 0)
{
List<Mobile> toDelete = BuildFinanceList();
while (Silver + flow < 0 && toDelete.Count > 0)
{
int index = Utility.Random(toDelete.Count);
Mobile mob = toDelete[index];
mob.Delete();
toDelete.RemoveAt(index);
flow = NetCashFlow;
}
}
Silver += flow;
}
public List<Mobile> BuildFinanceList()
{
List<Mobile> list = new List<Mobile>();
for (int i = 0; i < VendorLists.Count; ++i)
list.AddRange(VendorLists[i].Vendors);
for (int i = 0; i < GuardLists.Count; ++i)
list.AddRange(GuardLists[i].Guards);
return list;
}
public void ConstructGuardLists()
{
GuardDefinition[] defs = Owner == null ? new GuardDefinition[0] : Owner.Definition.Guards;
GuardLists = new List<GuardList>();
for (int i = 0; i < defs.Length; ++i)
GuardLists.Add(new GuardList(defs[i]));
}
public GuardList FindGuardList(Type type)
{
List<GuardList> guardLists = GuardLists;
for (int i = 0; i < guardLists.Count; ++i)
{
GuardList guardList = guardLists[i];
if (guardList.Definition.Type == type)
return guardList;
}
return null;
}
public void ConstructVendorLists()
{
VendorDefinition[] defs = VendorDefinition.Definitions;
VendorLists = new List<VendorList>();
for (int i = 0; i < defs.Length; ++i)
VendorLists.Add(new VendorList(defs[i]));
}
public VendorList FindVendorList(Type type)
{
List<VendorList> vendorLists = VendorLists;
for (int i = 0; i < vendorLists.Count; ++i)
{
VendorList vendorList = vendorLists[i];
if (vendorList.Definition.Type == type)
return vendorList;
}
return null;
}
public bool RegisterGuard(BaseFactionGuard guard)
{
if (guard == null)
return false;
GuardList guardList = FindGuardList(guard.GetType());
if (guardList == null)
return false;
guardList.Guards.Add(guard);
return true;
}
public bool UnregisterGuard(BaseFactionGuard guard)
{
if (guard == null)
return false;
GuardList guardList = FindGuardList(guard.GetType());
if (guardList == null)
return false;
if (!guardList.Guards.Contains(guard))
return false;
guardList.Guards.Remove(guard);
return true;
}
public bool RegisterVendor(BaseFactionVendor vendor)
{
if (vendor == null)
return false;
VendorList vendorList = FindVendorList(vendor.GetType());
if (vendorList == null)
return false;
vendorList.Vendors.Add(vendor);
return true;
}
public bool UnregisterVendor(BaseFactionVendor vendor)
{
if (vendor == null)
return false;
VendorList vendorList = FindVendorList(vendor.GetType());
if (vendorList == null)
return false;
if (!vendorList.Vendors.Contains(vendor))
return false;
vendorList.Vendors.Remove(vendor);
return true;
}
public static void Initialize()
{
List<Town> towns = Towns;
for (int i = 0; i < towns.Count; ++i)
{
towns[i].Sheriff = towns[i].Sheriff;
towns[i].Finance = towns[i].Finance;
}
CommandSystem.Register("GrantTownSilver", AccessLevel.Administrator, GrantTownSilver_OnCommand);
}
public bool IsSheriff(Mobile mob)
{
return mob?.Deleted == false &&
(mob.AccessLevel >= AccessLevel.GameMaster || mob == Sheriff);
}
public bool IsFinance(Mobile mob)
{
return mob?.Deleted == false &&
(mob.AccessLevel >= AccessLevel.GameMaster || mob == Finance);
}
public void Capture(Faction f)
{
if (m_State.Owner == f)
return;
if (m_State.Owner == null) // going from unowned to owned
{
LastIncome = DateTime.UtcNow;
f.Silver += SilverCaptureBonus;
}
else if (f == null) // going from owned to unowned
{
LastIncome = DateTime.MinValue;
}
else // otherwise changing hands, income timer doesn't change
{
f.Silver += SilverCaptureBonus;
}
m_State.Owner = f;
Sheriff = null;
Finance = null;
TownMonolith monolith = Monolith;
if (monolith != null)
monolith.Faction = f;
List<VendorList> vendorLists = VendorLists;
for (int i = 0; i < vendorLists.Count; ++i)
{
VendorList vendorList = vendorLists[i];
List<BaseFactionVendor> vendors = vendorList.Vendors;
for (int j = vendors.Count - 1; j >= 0; --j)
vendors[j].Delete();
}
List<GuardList> guardLists = GuardLists;
for (int i = 0; i < guardLists.Count; ++i)
{
GuardList guardList = guardLists[i];
List<BaseFactionGuard> guards = guardList.Guards;
for (int j = guards.Count - 1; j >= 0; --j)
guards[j].Delete();
}
ConstructGuardLists();
}
public override string ToString()
{
return Definition.FriendlyName;
}
public static void WriteReference(GenericWriter writer, Town town)
{
int idx = Towns.IndexOf(town);
writer.WriteEncodedInt(idx + 1);
}
public static Town ReadReference(GenericReader reader)
{
int idx = reader.ReadEncodedInt() - 1;
if (idx >= 0 && idx < Towns.Count)
return Towns[idx];
return null;
}
public static Town Parse(string name)
{
List<Town> towns = Towns;
for (int i = 0; i < towns.Count; ++i)
{
Town town = towns[i];
if (Insensitive.Equals(town.Definition.FriendlyName, name))
return town;
}
return null;
}
public static void GrantTownSilver_OnCommand(CommandEventArgs e)
{
Town town = FromRegion(e.Mobile.Region);
if (town == null)
{
e.Mobile.SendMessage("You are not in a faction town.");
}
else if (e.Length == 0)
{
e.Mobile.SendMessage("Format: GrantTownSilver <amount>");
}
else
{
town.Silver += e.GetInt32(0);
e.Mobile.SendMessage("You have granted {0:N0} silver to the town. It now has {1:N0} silver.", e.GetInt32(0),
town.Silver);
}
}
}
}

View file

@ -0,0 +1,135 @@
using System;
namespace Server.Factions
{
public class TownState
{
private Mobile m_Finance;
private Mobile m_Sheriff;
public TownState(Town town)
{
Town = town;
}
public TownState(GenericReader reader)
{
int version = reader.ReadEncodedInt();
switch (version)
{
case 3:
{
LastIncome = reader.ReadDateTime();
goto case 2;
}
case 2:
{
Tax = reader.ReadEncodedInt();
LastTaxChange = reader.ReadDateTime();
goto case 1;
}
case 1:
{
Silver = reader.ReadEncodedInt();
goto case 0;
}
case 0:
{
Town = Town.ReadReference(reader);
Owner = Faction.ReadReference(reader);
m_Sheriff = reader.ReadMobile();
m_Finance = reader.ReadMobile();
Town.State = this;
break;
}
}
}
public Town Town{ get; set; }
public Faction Owner{ get; set; }
public Mobile Sheriff
{
get => m_Sheriff;
set
{
if (m_Sheriff != null)
{
PlayerState pl = PlayerState.Find(m_Sheriff);
if (pl != null)
pl.Sheriff = null;
}
m_Sheriff = value;
if (m_Sheriff != null)
{
PlayerState pl = PlayerState.Find(m_Sheriff);
if (pl != null)
pl.Sheriff = Town;
}
}
}
public Mobile Finance
{
get => m_Finance;
set
{
if (m_Finance != null)
{
PlayerState pl = PlayerState.Find(m_Finance);
if (pl != null)
pl.Finance = null;
}
m_Finance = value;
if (m_Finance != null)
{
PlayerState pl = PlayerState.Find(m_Finance);
if (pl != null)
pl.Finance = Town;
}
}
}
public int Silver{ get; set; }
public int Tax{ get; set; }
public DateTime LastTaxChange{ get; set; }
public DateTime LastIncome{ get; set; }
public void Serialize(GenericWriter writer)
{
writer.WriteEncodedInt(3); // version
writer.Write(LastIncome);
writer.WriteEncodedInt(Tax);
writer.Write(LastTaxChange);
writer.WriteEncodedInt(Silver);
Town.WriteReference(writer, Town);
Faction.WriteReference(writer, Owner);
writer.Write(m_Sheriff);
writer.Write(m_Finance);
}
}
}

View file

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
namespace Server.Factions
{
public class VendorList
{
public VendorList(VendorDefinition definition)
{
Definition = definition;
Vendors = new List<BaseFactionVendor>();
}
public VendorDefinition Definition{ get; }
public List<BaseFactionVendor> Vendors{ get; }
public BaseFactionVendor Construct(Town town, Faction faction)
{
try
{
return Activator.CreateInstance(Definition.Type, town, faction) as BaseFactionVendor;
}
catch
{
return null;
}
}
}
}