Reorganizes Project (#41)
This commit is contained in:
parent
08bf44af9a
commit
3614a66aee
3499 changed files with 79 additions and 55 deletions
553
Projects/Scripts/Engines/Factions/Core/Election.cs
Normal file
553
Projects/Scripts/Engines/Factions/Core/Election.cs
Normal 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
|
||||
}
|
||||
}
|
||||
1371
Projects/Scripts/Engines/Factions/Core/Faction.cs
Normal file
1371
Projects/Scripts/Engines/Factions/Core/Faction.cs
Normal file
File diff suppressed because it is too large
Load diff
137
Projects/Scripts/Engines/Factions/Core/FactionItem.cs
Normal file
137
Projects/Scripts/Engines/Factions/Core/FactionItem.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
273
Projects/Scripts/Engines/Factions/Core/FactionState.cs
Normal file
273
Projects/Scripts/Engines/Factions/Core/FactionState.cs
Normal 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
75
Projects/Scripts/Engines/Factions/Core/Generator.cs
Normal file
75
Projects/Scripts/Engines/Factions/Core/Generator.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Projects/Scripts/Engines/Factions/Core/GuardList.cs
Normal file
30
Projects/Scripts/Engines/Factions/Core/GuardList.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
154
Projects/Scripts/Engines/Factions/Core/Keywords.cs
Normal file
154
Projects/Scripts/Engines/Factions/Core/Keywords.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
92
Projects/Scripts/Engines/Factions/Core/MerchantTitles.cs
Normal file
92
Projects/Scripts/Engines/Factions/Core/MerchantTitles.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
90
Projects/Scripts/Engines/Factions/Core/Persistance.cs
Normal file
90
Projects/Scripts/Engines/Factions/Core/Persistance.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
303
Projects/Scripts/Engines/Factions/Core/PlayerState.cs
Normal file
303
Projects/Scripts/Engines/Factions/Core/PlayerState.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
78
Projects/Scripts/Engines/Factions/Core/Reflector.cs
Normal file
78
Projects/Scripts/Engines/Factions/Core/Reflector.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
Projects/Scripts/Engines/Factions/Core/SilverGivenEntry.cs
Normal file
21
Projects/Scripts/Engines/Factions/Core/SilverGivenEntry.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
40
Projects/Scripts/Engines/Factions/Core/StrongholdRegion.cs
Normal file
40
Projects/Scripts/Engines/Factions/Core/StrongholdRegion.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
505
Projects/Scripts/Engines/Factions/Core/Town.cs
Normal file
505
Projects/Scripts/Engines/Factions/Core/Town.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
135
Projects/Scripts/Engines/Factions/Core/TownState.cs
Normal file
135
Projects/Scripts/Engines/Factions/Core/TownState.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Projects/Scripts/Engines/Factions/Core/VendorList.cs
Normal file
30
Projects/Scripts/Engines/Factions/Core/VendorList.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class FactionDefinition
|
||||
{
|
||||
public FactionDefinition(int sort, int huePrimary, int hueSecondary, int hueJoin, int hueBroadcast, int warHorseBody,
|
||||
int warHorseItem, string friendlyName, string keyword, string abbreviation, TextDefinition name,
|
||||
TextDefinition propName, TextDefinition header, TextDefinition about, TextDefinition cityControl,
|
||||
TextDefinition sigilControl, TextDefinition signupName, TextDefinition factionStoneName,
|
||||
TextDefinition ownerLabel, TextDefinition guardIgnore, TextDefinition guardWarn, TextDefinition guardAttack,
|
||||
StrongholdDefinition stronghold, RankDefinition[] ranks, GuardDefinition[] guards)
|
||||
{
|
||||
Sort = sort;
|
||||
HuePrimary = huePrimary;
|
||||
HueSecondary = hueSecondary;
|
||||
HueJoin = hueJoin;
|
||||
HueBroadcast = hueBroadcast;
|
||||
WarHorseBody = warHorseBody;
|
||||
WarHorseItem = warHorseItem;
|
||||
FriendlyName = friendlyName;
|
||||
Keyword = keyword;
|
||||
Abbreviation = abbreviation;
|
||||
Name = name;
|
||||
PropName = propName;
|
||||
Header = header;
|
||||
About = about;
|
||||
CityControl = cityControl;
|
||||
SigilControl = sigilControl;
|
||||
SignupName = signupName;
|
||||
FactionStoneName = factionStoneName;
|
||||
OwnerLabel = ownerLabel;
|
||||
GuardIgnore = guardIgnore;
|
||||
GuardWarn = guardWarn;
|
||||
GuardAttack = guardAttack;
|
||||
Stronghold = stronghold;
|
||||
Ranks = ranks;
|
||||
Guards = guards;
|
||||
}
|
||||
|
||||
public int Sort{ get; }
|
||||
|
||||
public int HuePrimary{ get; }
|
||||
|
||||
public int HueSecondary{ get; }
|
||||
|
||||
public int HueJoin{ get; }
|
||||
|
||||
public int HueBroadcast{ get; }
|
||||
|
||||
public int WarHorseBody{ get; }
|
||||
|
||||
public int WarHorseItem{ get; }
|
||||
|
||||
public string FriendlyName{ get; }
|
||||
|
||||
public string Keyword{ get; }
|
||||
|
||||
public string Abbreviation{ get; }
|
||||
|
||||
public TextDefinition Name{ get; }
|
||||
|
||||
public TextDefinition PropName{ get; }
|
||||
|
||||
public TextDefinition Header{ get; }
|
||||
|
||||
public TextDefinition About{ get; }
|
||||
|
||||
public TextDefinition CityControl{ get; }
|
||||
|
||||
public TextDefinition SigilControl{ get; }
|
||||
|
||||
public TextDefinition SignupName{ get; }
|
||||
|
||||
public TextDefinition FactionStoneName{ get; }
|
||||
|
||||
public TextDefinition OwnerLabel{ get; }
|
||||
|
||||
public TextDefinition GuardIgnore{ get; }
|
||||
|
||||
public TextDefinition GuardWarn{ get; }
|
||||
|
||||
public TextDefinition GuardAttack{ get; }
|
||||
|
||||
public StrongholdDefinition Stronghold{ get; }
|
||||
|
||||
public RankDefinition[] Ranks{ get; }
|
||||
|
||||
public GuardDefinition[] Guards{ get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionItemDefinition
|
||||
{
|
||||
private static FactionItemDefinition m_MetalArmor = new FactionItemDefinition(1000, typeof(Blacksmith));
|
||||
private static FactionItemDefinition m_Weapon = new FactionItemDefinition(1000, typeof(Blacksmith));
|
||||
private static FactionItemDefinition m_RangedWeapon = new FactionItemDefinition(1000, typeof(Bowyer));
|
||||
private static FactionItemDefinition m_LeatherArmor = new FactionItemDefinition(750, typeof(Tailor));
|
||||
private static FactionItemDefinition m_Clothing = new FactionItemDefinition(200, typeof(Tailor));
|
||||
private static FactionItemDefinition m_Scroll = new FactionItemDefinition(500, typeof(Mage));
|
||||
|
||||
public FactionItemDefinition(int silverCost, Type vendorType)
|
||||
{
|
||||
SilverCost = silverCost;
|
||||
VendorType = vendorType;
|
||||
}
|
||||
|
||||
public int SilverCost{ get; }
|
||||
|
||||
public Type VendorType{ get; }
|
||||
|
||||
public static FactionItemDefinition Identify(Item item)
|
||||
{
|
||||
if (item is BaseArmor armor)
|
||||
{
|
||||
if (CraftResources.GetType(armor.Resource) == CraftResourceType.Leather)
|
||||
return m_LeatherArmor;
|
||||
|
||||
return m_MetalArmor;
|
||||
}
|
||||
|
||||
if (item is BaseRanged)
|
||||
return m_RangedWeapon;
|
||||
if (item is BaseWeapon)
|
||||
return m_Weapon;
|
||||
if (item is BaseClothing)
|
||||
return m_Clothing;
|
||||
if (item is SpellScroll)
|
||||
return m_Scroll;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class GuardDefinition
|
||||
{
|
||||
public GuardDefinition(Type type, int itemID, int price, int upkeep, int maximum, TextDefinition header,
|
||||
TextDefinition label)
|
||||
{
|
||||
Type = type;
|
||||
|
||||
Price = price;
|
||||
Upkeep = upkeep;
|
||||
Maximum = maximum;
|
||||
ItemID = itemID;
|
||||
|
||||
Header = header;
|
||||
Label = label;
|
||||
}
|
||||
|
||||
public Type Type{ get; }
|
||||
|
||||
public int Price{ get; }
|
||||
|
||||
public int Upkeep{ get; }
|
||||
|
||||
public int Maximum{ get; }
|
||||
|
||||
public int ItemID{ get; }
|
||||
|
||||
public TextDefinition Header{ get; }
|
||||
|
||||
public TextDefinition Label{ get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class RankDefinition
|
||||
{
|
||||
public RankDefinition(int rank, int required, int maxWearables, TextDefinition title)
|
||||
{
|
||||
Rank = rank;
|
||||
Required = required;
|
||||
Title = title;
|
||||
MaxWearables = maxWearables;
|
||||
}
|
||||
|
||||
public int Rank{ get; }
|
||||
|
||||
public int Required{ get; }
|
||||
|
||||
public int MaxWearables{ get; }
|
||||
|
||||
public TextDefinition Title{ get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class StrongholdDefinition
|
||||
{
|
||||
public StrongholdDefinition(Rectangle2D[] area, Point3D joinStone, Point3D factionStone, Point3D[] monoliths)
|
||||
{
|
||||
Area = area;
|
||||
JoinStone = joinStone;
|
||||
FactionStone = factionStone;
|
||||
Monoliths = monoliths;
|
||||
}
|
||||
|
||||
public Rectangle2D[] Area{ get; }
|
||||
|
||||
public Point3D JoinStone{ get; }
|
||||
|
||||
public Point3D FactionStone{ get; }
|
||||
|
||||
public Point3D[] Monoliths{ get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class TownDefinition
|
||||
{
|
||||
public TownDefinition(int sort, int sigilID, string region, string friendlyName, TextDefinition townName,
|
||||
TextDefinition townStoneHeader, TextDefinition strongholdMonolithName, TextDefinition townMonolithName,
|
||||
TextDefinition townStoneName, TextDefinition sigilName, TextDefinition corruptedSigilName, Point3D monolith,
|
||||
Point3D townStone)
|
||||
{
|
||||
Sort = sort;
|
||||
SigilID = sigilID;
|
||||
Region = region;
|
||||
FriendlyName = friendlyName;
|
||||
TownName = townName;
|
||||
TownStoneHeader = townStoneHeader;
|
||||
StrongholdMonolithName = strongholdMonolithName;
|
||||
TownMonolithName = townMonolithName;
|
||||
TownStoneName = townStoneName;
|
||||
SigilName = sigilName;
|
||||
CorruptedSigilName = corruptedSigilName;
|
||||
Monolith = monolith;
|
||||
TownStone = townStone;
|
||||
}
|
||||
|
||||
public int Sort{ get; }
|
||||
|
||||
public int SigilID{ get; }
|
||||
|
||||
public string Region{ get; }
|
||||
|
||||
public string FriendlyName{ get; }
|
||||
|
||||
public TextDefinition TownName{ get; }
|
||||
|
||||
public TextDefinition TownStoneHeader{ get; }
|
||||
|
||||
public TextDefinition StrongholdMonolithName{ get; }
|
||||
|
||||
public TextDefinition TownMonolithName{ get; }
|
||||
|
||||
public TextDefinition TownStoneName{ get; }
|
||||
|
||||
public TextDefinition SigilName{ get; }
|
||||
|
||||
public TextDefinition CorruptedSigilName{ get; }
|
||||
|
||||
public Point3D Monolith{ get; }
|
||||
|
||||
public Point3D TownStone{ get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class VendorDefinition
|
||||
{
|
||||
public VendorDefinition(Type type, int itemID, int price, int upkeep, int maximum, TextDefinition header,
|
||||
TextDefinition label)
|
||||
{
|
||||
Type = type;
|
||||
|
||||
Price = price;
|
||||
Upkeep = upkeep;
|
||||
Maximum = maximum;
|
||||
ItemID = itemID;
|
||||
|
||||
Header = header;
|
||||
Label = label;
|
||||
}
|
||||
|
||||
public Type Type{ get; }
|
||||
|
||||
public int Price{ get; }
|
||||
|
||||
public int Upkeep{ get; }
|
||||
|
||||
public int Maximum{ get; }
|
||||
|
||||
public int ItemID{ get; }
|
||||
|
||||
public TextDefinition Header{ get; }
|
||||
|
||||
public TextDefinition Label{ get; }
|
||||
|
||||
public static VendorDefinition[] Definitions{ get; } =
|
||||
{
|
||||
new VendorDefinition(typeof(FactionBottleVendor), 0xF0E,
|
||||
5000,
|
||||
1000,
|
||||
10,
|
||||
new TextDefinition(1011549, "POTION BOTTLE VENDOR"),
|
||||
new TextDefinition(1011544, "Buy Potion Bottle Vendor")
|
||||
),
|
||||
new VendorDefinition(typeof(FactionBoardVendor), 0x1BD7,
|
||||
3000,
|
||||
500,
|
||||
10,
|
||||
new TextDefinition(1011552, "WOOD VENDOR"),
|
||||
new TextDefinition(1011545, "Buy Wooden Board Vendor")
|
||||
),
|
||||
new VendorDefinition(typeof(FactionOreVendor), 0x19B8,
|
||||
3000,
|
||||
500,
|
||||
10,
|
||||
new TextDefinition(1011553, "IRON ORE VENDOR"),
|
||||
new TextDefinition(1011546, "Buy Iron Ore Vendor")
|
||||
),
|
||||
new VendorDefinition(typeof(FactionReagentVendor), 0xF86,
|
||||
5000,
|
||||
1000,
|
||||
10,
|
||||
new TextDefinition(1011554, "REAGENT VENDOR"),
|
||||
new TextDefinition(1011547, "Buy Reagent Vendor")
|
||||
),
|
||||
new VendorDefinition(typeof(FactionHorseVendor), 0x20DD,
|
||||
5000,
|
||||
1000,
|
||||
1,
|
||||
new TextDefinition(1011556, "HORSE BREEDER"),
|
||||
new TextDefinition(1011555, "Buy Horse Breeder")
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
127
Projects/Scripts/Engines/Factions/Gumps/ElectionGump.cs
Normal file
127
Projects/Scripts/Engines/Factions/Gumps/ElectionGump.cs
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
using System;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class ElectionGump : FactionGump
|
||||
{
|
||||
private Election m_Election;
|
||||
private PlayerMobile m_From;
|
||||
|
||||
public ElectionGump(PlayerMobile from, Election election) : base(50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Election = election;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 420, 180, 5054);
|
||||
AddBackground(10, 10, 400, 160, 3000);
|
||||
|
||||
AddHtmlText(20, 20, 380, 20, election.Faction.Definition.Header, false, false);
|
||||
|
||||
// NOTE: Gump not entirely OSI-accurate, intentionally so
|
||||
|
||||
switch (election.State)
|
||||
{
|
||||
case ElectionState.Pending:
|
||||
{
|
||||
TimeSpan toGo = election.LastStateTime + Election.PendingPeriod - DateTime.UtcNow;
|
||||
int days = (int)(toGo.TotalDays + 0.5);
|
||||
|
||||
AddHtmlLocalized(20, 40, 380, 20, 1038034); // A new election campaign is pending
|
||||
|
||||
if (days > 0)
|
||||
{
|
||||
AddHtmlLocalized(20, 60, 280, 20, 1018062); // Days until next election :
|
||||
AddLabel(300, 60, 0, days.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
AddHtmlLocalized(20, 60, 280, 20, 1018059); // Election campaigning begins tonight.
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ElectionState.Campaign:
|
||||
{
|
||||
TimeSpan toGo = election.LastStateTime + Election.CampaignPeriod - DateTime.UtcNow;
|
||||
int days = (int)(toGo.TotalDays + 0.5);
|
||||
|
||||
AddHtmlLocalized(20, 40, 380, 20, 1018058); // There is an election campaign in progress.
|
||||
|
||||
if (days > 0)
|
||||
{
|
||||
AddHtmlLocalized(20, 60, 280, 20, 1038033); // Days to go:
|
||||
AddLabel(300, 60, 0, days.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
AddHtmlLocalized(20, 60, 280, 20, 1018061); // Campaign in progress. Voting begins tonight.
|
||||
}
|
||||
|
||||
if (m_Election.CanBeCandidate(m_From))
|
||||
{
|
||||
AddButton(20, 110, 4005, 4007, 2);
|
||||
AddHtmlLocalized(55, 110, 350, 20, 1011427); // CAMPAIGN FOR LEADERSHIP
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerState pl = PlayerState.Find(m_From);
|
||||
|
||||
if (pl == null || pl.Rank.Rank < Election.CandidateRank)
|
||||
AddHtmlLocalized(20, 100, 380, 20, 1010118); // You must have a higher rank to run for office
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ElectionState.Election:
|
||||
{
|
||||
TimeSpan toGo = election.LastStateTime + Election.VotingPeriod - DateTime.UtcNow;
|
||||
int days = (int)Math.Ceiling(toGo.TotalDays);
|
||||
|
||||
AddHtmlLocalized(20, 40, 380, 20, 1018060); // There is an election vote in progress.
|
||||
|
||||
AddHtmlLocalized(20, 60, 280, 20, 1038033);
|
||||
AddLabel(300, 60, 0, days.ToString());
|
||||
|
||||
AddHtmlLocalized(55, 100, 380, 20, 1011428); // VOTE FOR LEADERSHIP
|
||||
AddButton(20, 100, 4005, 4007, 1);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AddButton(20, 140, 4005, 4007, 0);
|
||||
AddHtmlLocalized(55, 140, 350, 20, 1011012); // CANCEL
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
switch (info.ButtonID)
|
||||
{
|
||||
case 0: // back
|
||||
{
|
||||
m_From.SendGump(new FactionStoneGump(m_From, m_Election.Faction));
|
||||
break;
|
||||
}
|
||||
case 1: // vote
|
||||
{
|
||||
if (m_Election.State == ElectionState.Election)
|
||||
m_From.SendGump(new VoteGump(m_From, m_Election));
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: // campaign
|
||||
{
|
||||
if (m_Election.CanBeCandidate(m_From))
|
||||
m_Election.AddCandidate(m_From);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class ElectionManagementGump : Gump
|
||||
{
|
||||
public const int LabelColor = 0xFFFFFF;
|
||||
private Candidate m_Candidate;
|
||||
|
||||
private Election m_Election;
|
||||
private int m_Page;
|
||||
|
||||
public ElectionManagementGump(Election election, Candidate candidate = null, int page = 0) : base(40, 40)
|
||||
{
|
||||
m_Election = election;
|
||||
m_Candidate = candidate;
|
||||
m_Page = page;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
if (candidate != null)
|
||||
{
|
||||
AddBackground(0, 0, 448, 354, 9270);
|
||||
AddAlphaRegion(10, 10, 428, 334);
|
||||
|
||||
AddHtml(10, 10, 428, 20, Color(Center("Candidate Management"), LabelColor));
|
||||
|
||||
AddHtml(45, 35, 100, 20, Color("Player Name:", LabelColor));
|
||||
AddHtml(145, 35, 100, 20, Color(candidate.Mobile == null ? "null" : candidate.Mobile.Name, LabelColor));
|
||||
|
||||
AddHtml(45, 55, 100, 20, Color("Vote Count:", LabelColor));
|
||||
AddHtml(145, 55, 100, 20, Color(candidate.Votes.ToString(), LabelColor));
|
||||
|
||||
AddButton(12, 73, 4005, 4007, 1);
|
||||
AddHtml(45, 75, 100, 20, Color("Drop Candidate", LabelColor));
|
||||
|
||||
AddImageTiled(13, 99, 422, 242, 9264);
|
||||
AddImageTiled(14, 100, 420, 240, 9274);
|
||||
AddAlphaRegion(14, 100, 420, 240);
|
||||
|
||||
AddHtml(14, 100, 420, 20, Color(Center("Voters"), LabelColor));
|
||||
|
||||
if (page > 0)
|
||||
AddButton(397, 104, 0x15E3, 0x15E7, 2);
|
||||
else
|
||||
AddImage(397, 104, 0x25EA);
|
||||
|
||||
if ((page + 1) * 10 < candidate.Voters.Count)
|
||||
AddButton(414, 104, 0x15E1, 0x15E5, 3);
|
||||
else
|
||||
AddImage(414, 104, 0x25E6);
|
||||
|
||||
|
||||
AddHtml(14, 120, 30, 20, Color(Center("DEL"), LabelColor));
|
||||
AddHtml(47, 120, 150, 20, Color("Name", LabelColor));
|
||||
AddHtml(195, 120, 100, 20, Color(Center("Address"), LabelColor));
|
||||
AddHtml(295, 120, 80, 20, Color(Center("Time"), LabelColor));
|
||||
AddHtml(355, 120, 60, 20, Color(Center("Legit"), LabelColor));
|
||||
|
||||
int idx = 0;
|
||||
|
||||
for (int i = page * 10; i >= 0 && i < candidate.Voters.Count && i < (page + 1) * 10; ++i, ++idx)
|
||||
{
|
||||
Voter voter = candidate.Voters[i];
|
||||
|
||||
AddButton(13, 138 + idx * 20, 4002, 4004, 4 + i);
|
||||
|
||||
object[] fields = voter.AcquireFields();
|
||||
|
||||
int x = 45;
|
||||
|
||||
for (int j = 0; j < fields.Length; ++j)
|
||||
{
|
||||
object obj = fields[j];
|
||||
|
||||
if (obj is Mobile mobile)
|
||||
{
|
||||
AddHtml(x + 2, 140 + idx * 20, 150, 20, Color(mobile.Name, LabelColor));
|
||||
x += 150;
|
||||
}
|
||||
else if (obj is IPAddress)
|
||||
{
|
||||
AddHtml(x, 140 + idx * 20, 100, 20, Color(Center(obj.ToString()), LabelColor));
|
||||
x += 100;
|
||||
}
|
||||
else if (obj is DateTime time)
|
||||
{
|
||||
AddHtml(x, 140 + idx * 20, 80, 20,
|
||||
Color(Center(FormatTimeSpan(time - election.LastStateTime)), LabelColor));
|
||||
x += 80;
|
||||
}
|
||||
else if (obj is int i1)
|
||||
{
|
||||
AddHtml(x, 140 + idx * 20, 60, 20, Color(Center(i1 + "%"), LabelColor));
|
||||
x += 60;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddBackground(0, 0, 288, 334, 9270);
|
||||
AddAlphaRegion(10, 10, 268, 314);
|
||||
|
||||
AddHtml(10, 10, 268, 20, Color(Center("Election Management"), LabelColor));
|
||||
|
||||
AddHtml(45, 35, 100, 20, Color("Current State:", LabelColor));
|
||||
AddHtml(145, 35, 100, 20, Color(election.State.ToString(), LabelColor));
|
||||
|
||||
AddButton(12, 53, 4005, 4007, 1);
|
||||
AddHtml(45, 55, 100, 20, Color("Transition Time:", LabelColor));
|
||||
AddHtml(145, 55, 100, 20, Color(FormatTimeSpan(election.NextStateTime), LabelColor));
|
||||
|
||||
AddImageTiled(13, 79, 262, 242, 9264);
|
||||
AddImageTiled(14, 80, 260, 240, 9274);
|
||||
AddAlphaRegion(14, 80, 260, 240);
|
||||
|
||||
AddHtml(14, 80, 260, 20, Color(Center("Candidates"), LabelColor));
|
||||
AddHtml(14, 100, 30, 20, Color(Center("-->"), LabelColor));
|
||||
AddHtml(47, 100, 150, 20, Color("Name", LabelColor));
|
||||
AddHtml(195, 100, 80, 20, Color(Center("Votes"), LabelColor));
|
||||
|
||||
for (int i = 0; i < election.Candidates.Count; ++i)
|
||||
{
|
||||
Candidate cd = election.Candidates[i];
|
||||
Mobile mob = cd.Mobile;
|
||||
|
||||
if (mob == null)
|
||||
continue;
|
||||
|
||||
AddButton(13, 118 + i * 20, 4005, 4007, 2 + i);
|
||||
AddHtml(47, 120 + i * 20, 150, 20, Color(mob.Name, LabelColor));
|
||||
AddHtml(195, 120 + i * 20, 80, 20, Color(Center(cd.Votes.ToString()), LabelColor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Right(string text)
|
||||
{
|
||||
return $"<DIV ALIGN=RIGHT>{text}</DIV>";
|
||||
}
|
||||
|
||||
public string Center(string text)
|
||||
{
|
||||
return $"<CENTER>{text}</CENTER>";
|
||||
}
|
||||
|
||||
public string Color(string text, int color)
|
||||
{
|
||||
return $"<BASEFONT COLOR=#{color:X6}>{text}</BASEFONT>";
|
||||
}
|
||||
|
||||
public static string FormatTimeSpan(TimeSpan ts)
|
||||
{
|
||||
return $"{ts.Days:D2}:{ts.Hours % 24:D2}:{ts.Minutes % 60:D2}:{ts.Seconds % 60:D2}";
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
Mobile from = sender.Mobile;
|
||||
int bid = info.ButtonID;
|
||||
|
||||
if (m_Candidate == null)
|
||||
{
|
||||
if (bid == 0)
|
||||
{
|
||||
}
|
||||
else if (bid == 1)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
bid -= 2;
|
||||
|
||||
if (bid >= 0 && bid < m_Election.Candidates.Count)
|
||||
from.SendGump(new ElectionManagementGump(m_Election, m_Election.Candidates[bid]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bid == 0)
|
||||
{
|
||||
from.SendGump(new ElectionManagementGump(m_Election));
|
||||
}
|
||||
else if (bid == 1)
|
||||
{
|
||||
m_Election.RemoveCandidate(m_Candidate.Mobile);
|
||||
from.SendGump(new ElectionManagementGump(m_Election));
|
||||
}
|
||||
else if (bid == 2 && m_Page > 0)
|
||||
{
|
||||
from.SendGump(new ElectionManagementGump(m_Election, m_Candidate, m_Page - 1));
|
||||
}
|
||||
else if (bid == 3 && (m_Page + 1) * 10 < m_Candidate.Voters.Count)
|
||||
{
|
||||
from.SendGump(new ElectionManagementGump(m_Election, m_Candidate, m_Page + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
bid -= 4;
|
||||
|
||||
if (bid >= 0 && bid < m_Candidate.Voters.Count)
|
||||
{
|
||||
m_Candidate.Voters.RemoveAt(bid);
|
||||
from.SendGump(new ElectionManagementGump(m_Election, m_Candidate, m_Page));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
46
Projects/Scripts/Engines/Factions/Gumps/FactionGump.cs
Normal file
46
Projects/Scripts/Engines/Factions/Gumps/FactionGump.cs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
using Server.Gumps;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public abstract class FactionGump : Gump
|
||||
{
|
||||
public FactionGump(int x, int y) : base(x, y)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual int ButtonTypes => 10;
|
||||
|
||||
public int ToButtonID(int type, int index)
|
||||
{
|
||||
return 1 + index * ButtonTypes + type;
|
||||
}
|
||||
|
||||
public bool FromButtonID(int buttonID, out int type, out int index)
|
||||
{
|
||||
int offset = buttonID - 1;
|
||||
|
||||
if (offset >= 0)
|
||||
{
|
||||
type = offset % ButtonTypes;
|
||||
index = offset / ButtonTypes;
|
||||
return true;
|
||||
}
|
||||
|
||||
type = index = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool Exists(Mobile mob)
|
||||
{
|
||||
return mob.HasGump<FactionGump>();
|
||||
}
|
||||
|
||||
public void AddHtmlText(int x, int y, int width, int height, TextDefinition text, bool back, bool scroll)
|
||||
{
|
||||
if (text?.Number > 0)
|
||||
AddHtmlLocalized(x, y, width, height, text.Number, back, scroll);
|
||||
else if (text?.String != null)
|
||||
AddHtml(x, y, width, height, text.String, back, scroll);
|
||||
}
|
||||
}
|
||||
}
|
||||
100
Projects/Scripts/Engines/Factions/Gumps/FactionImbueGump.cs
Normal file
100
Projects/Scripts/Engines/Factions/Gumps/FactionImbueGump.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
using Server.Engines.Craft;
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionImbueGump : FactionGump
|
||||
{
|
||||
private CraftSystem m_CraftSystem;
|
||||
|
||||
private FactionItemDefinition m_Definition;
|
||||
private Faction m_Faction;
|
||||
private Item m_Item;
|
||||
private Mobile m_Mobile;
|
||||
private object m_Notice;
|
||||
private BaseTool m_Tool;
|
||||
|
||||
public FactionImbueGump(int quality, Item item, Mobile from, CraftSystem craftSystem, BaseTool tool, object notice,
|
||||
int availableSilver, Faction faction, FactionItemDefinition def) : base(100, 200)
|
||||
{
|
||||
m_Item = item;
|
||||
m_Mobile = from;
|
||||
m_Faction = faction;
|
||||
m_CraftSystem = craftSystem;
|
||||
m_Tool = tool;
|
||||
m_Notice = notice;
|
||||
m_Definition = def;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 320, 270, 5054);
|
||||
AddBackground(10, 10, 300, 250, 3000);
|
||||
|
||||
AddHtmlLocalized(20, 20, 210, 25, 1011569); // Imbue with Faction properties?
|
||||
|
||||
|
||||
AddHtmlLocalized(20, 60, 170, 25, 1018302); // Item quality:
|
||||
AddHtmlLocalized(175, 60, 100, 25, 1018305 - quality); // Exceptional, Average, Low
|
||||
|
||||
AddHtmlLocalized(20, 80, 170, 25, 1011572); // Item Cost :
|
||||
AddLabel(175, 80, 0x34, def.SilverCost.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(20, 100, 170, 25, 1011573); // Your Silver :
|
||||
AddLabel(175, 100, 0x34, availableSilver.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
|
||||
AddRadio(20, 140, 210, 211, true, 1);
|
||||
AddLabel(55, 140, m_Faction.Definition.HuePrimary - 1, "*****");
|
||||
AddHtmlLocalized(150, 140, 150, 25, 1011570); // Primary Color
|
||||
|
||||
AddRadio(20, 160, 210, 211, false, 2);
|
||||
AddLabel(55, 160, m_Faction.Definition.HueSecondary - 1, "*****");
|
||||
AddHtmlLocalized(150, 160, 150, 25, 1011571); // Secondary Color
|
||||
|
||||
|
||||
AddHtmlLocalized(55, 200, 200, 25, 1011011); // CONTINUE
|
||||
AddButton(20, 200, 4005, 4007, 1);
|
||||
|
||||
AddHtmlLocalized(55, 230, 200, 25, 1011012); // CANCEL
|
||||
AddButton(20, 230, 4005, 4007, 0);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID == 1)
|
||||
{
|
||||
Container pack = m_Mobile.Backpack;
|
||||
|
||||
if (pack != null && m_Item.IsChildOf(pack))
|
||||
{
|
||||
if (pack.ConsumeTotal(typeof(Silver), m_Definition.SilverCost))
|
||||
{
|
||||
int hue;
|
||||
|
||||
if (m_Item is SpellScroll)
|
||||
hue = 0;
|
||||
else if (info.IsSwitched(1))
|
||||
hue = m_Faction.Definition.HuePrimary;
|
||||
else
|
||||
hue = m_Faction.Definition.HueSecondary;
|
||||
|
||||
FactionItem.Imbue(m_Item, m_Faction, true, hue);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.SendLocalizedMessage(1042204); // You do not have enough silver.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Tool?.Deleted == false && m_Tool.UsesRemaining > 0)
|
||||
m_Mobile.SendGump(new CraftGump(m_Mobile, m_CraftSystem, m_Tool, m_Notice));
|
||||
else if (m_Notice is string s)
|
||||
m_Mobile.SendMessage(s);
|
||||
else if (m_Notice is int i && i > 0)
|
||||
m_Mobile.SendLocalizedMessage(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
357
Projects/Scripts/Engines/Factions/Gumps/FactionStoneGump.cs
Normal file
357
Projects/Scripts/Engines/Factions/Gumps/FactionStoneGump.cs
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionStoneGump : FactionGump
|
||||
{
|
||||
private Faction m_Faction;
|
||||
private PlayerMobile m_From;
|
||||
|
||||
public FactionStoneGump(PlayerMobile from, Faction faction) : base(20, 30)
|
||||
{
|
||||
m_From = from;
|
||||
m_Faction = faction;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 550, 440, 5054);
|
||||
AddBackground(10, 10, 530, 420, 3000);
|
||||
|
||||
#region General
|
||||
|
||||
AddPage(1);
|
||||
|
||||
AddHtmlText(20, 30, 510, 20, faction.Definition.Header, false, false);
|
||||
|
||||
AddHtmlLocalized(20, 60, 100, 20, 1011429); // Led By :
|
||||
AddHtml(125, 60, 200, 20, faction.Commander != null ? faction.Commander.Name : "Nobody");
|
||||
|
||||
AddHtmlLocalized(20, 80, 100, 20, 1011457); // Tithe rate :
|
||||
if (faction.Tithe >= 0 && faction.Tithe <= 100 && faction.Tithe % 10 == 0)
|
||||
AddHtmlLocalized(125, 80, 350, 20, 1011480 + faction.Tithe / 10);
|
||||
else
|
||||
AddHtml(125, 80, 350, 20, faction.Tithe + "%");
|
||||
|
||||
AddHtmlLocalized(20, 100, 100, 20, 1011458); // Traps placed :
|
||||
AddHtml(125, 100, 50, 20, faction.Traps.Count.ToString());
|
||||
|
||||
AddHtmlLocalized(55, 225, 200, 20, 1011428); // VOTE FOR LEADERSHIP
|
||||
AddButton(20, 225, 4005, 4007, ToButtonID(0, 0));
|
||||
|
||||
AddHtmlLocalized(55, 150, 100, 20, 1011430); // CITY STATUS
|
||||
AddButton(20, 150, 4005, 4007, 0, GumpButtonType.Page, 2);
|
||||
|
||||
AddHtmlLocalized(55, 175, 100, 20, 1011444); // STATISTICS
|
||||
AddButton(20, 175, 4005, 4007, 0, GumpButtonType.Page, 4);
|
||||
|
||||
bool isMerchantQualified = MerchantTitles.HasMerchantQualifications(from);
|
||||
|
||||
PlayerState pl = PlayerState.Find(from);
|
||||
|
||||
if (pl != null && pl.MerchantTitle != MerchantTitle.None)
|
||||
{
|
||||
AddHtmlLocalized(55, 200, 250, 20, 1011460); // UNDECLARE FACTION MERCHANT
|
||||
AddButton(20, 200, 4005, 4007, ToButtonID(1, 0));
|
||||
}
|
||||
else if (isMerchantQualified)
|
||||
{
|
||||
AddHtmlLocalized(55, 200, 250, 20, 1011459); // DECLARE FACTION MERCHANT
|
||||
AddButton(20, 200, 4005, 4007, 0, GumpButtonType.Page, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddHtmlLocalized(55, 200, 250, 20, 1011467); // MERCHANT OPTIONS
|
||||
AddImage(20, 200, 4020);
|
||||
}
|
||||
|
||||
AddHtmlLocalized(55, 250, 300, 20, 1011461); // COMMANDER OPTIONS
|
||||
if (faction.IsCommander(from))
|
||||
AddButton(20, 250, 4005, 4007, 0, GumpButtonType.Page, 6);
|
||||
else
|
||||
AddImage(20, 250, 4020);
|
||||
|
||||
AddHtmlLocalized(55, 275, 300, 20, 1011426); // LEAVE THIS FACTION
|
||||
AddButton(20, 275, 4005, 4007, ToButtonID(0, 1));
|
||||
|
||||
AddHtmlLocalized(55, 300, 200, 20, 1011441); // EXIT
|
||||
AddButton(20, 300, 4005, 4007, 0);
|
||||
|
||||
#endregion
|
||||
|
||||
#region City Status
|
||||
|
||||
AddPage(2);
|
||||
|
||||
AddHtmlLocalized(20, 30, 250, 20, 1011430); // CITY STATUS
|
||||
|
||||
List<Town> towns = Town.Towns;
|
||||
|
||||
for (int i = 0; i < towns.Count; ++i)
|
||||
{
|
||||
Town town = towns[i];
|
||||
|
||||
AddHtmlText(40, 55 + i * 30, 150, 20, town.Definition.TownName, false, false);
|
||||
|
||||
if (town.Owner == null)
|
||||
{
|
||||
AddHtmlLocalized(200, 55 + i * 30, 150, 20, 1011462); // : Neutral
|
||||
}
|
||||
else
|
||||
{
|
||||
AddHtmlLocalized(200, 55 + i * 30, 150, 20, town.Owner.Definition.OwnerLabel);
|
||||
|
||||
BaseMonolith monolith = town.Monolith;
|
||||
|
||||
AddImage(20, 60 + i * 30, monolith?.Sigil != null && monolith.Sigil.IsPurifying ? 0x938 : 0x939);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AddImage(20, 300, 2361);
|
||||
AddHtmlLocalized(45, 295, 300, 20, 1011491); // sigil may be recaptured
|
||||
|
||||
AddImage(20, 320, 2360);
|
||||
AddHtmlLocalized(45, 315, 300, 20, 1011492); // sigil may not be recaptured
|
||||
|
||||
AddHtmlLocalized(55, 350, 100, 20, 1011447); // BACK
|
||||
AddButton(20, 350, 4005, 4007, 0, GumpButtonType.Page, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Statistics
|
||||
|
||||
AddPage(4);
|
||||
|
||||
AddHtmlLocalized(20, 30, 150, 20, 1011444); // STATISTICS
|
||||
|
||||
AddHtmlLocalized(20, 100, 100, 20, 1011445); // Name :
|
||||
AddHtml(120, 100, 150, 20, from.Name);
|
||||
|
||||
AddHtmlLocalized(20, 130, 100, 20, 1018064); // score :
|
||||
AddHtml(120, 130, 100, 20, (pl?.KillPoints ?? 0).ToString());
|
||||
|
||||
AddHtmlLocalized(20, 160, 100, 20, 1011446); // Rank :
|
||||
AddHtml(120, 160, 100, 20, (pl?.Rank.Rank ?? 0).ToString());
|
||||
|
||||
AddHtmlLocalized(55, 250, 100, 20, 1011447); // BACK
|
||||
AddButton(20, 250, 4005, 4007, 0, GumpButtonType.Page, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Merchant Options
|
||||
|
||||
if ((pl == null || pl.MerchantTitle == MerchantTitle.None) && isMerchantQualified)
|
||||
{
|
||||
AddPage(5);
|
||||
|
||||
AddHtmlLocalized(20, 30, 250, 20, 1011467); // MERCHANT OPTIONS
|
||||
|
||||
AddHtmlLocalized(20, 80, 300, 20, 1011473); // Select the title you wish to display
|
||||
|
||||
MerchantTitleInfo[] infos = MerchantTitles.Info;
|
||||
|
||||
for (int i = 0; i < infos.Length; ++i)
|
||||
{
|
||||
MerchantTitleInfo info = infos[i];
|
||||
|
||||
if (MerchantTitles.IsQualified(from, info))
|
||||
AddButton(20, 100 + i * 30, 4005, 4007, ToButtonID(1, i + 1));
|
||||
else
|
||||
AddImage(20, 100 + i * 30, 4020);
|
||||
|
||||
AddHtmlText(55, 100 + i * 30, 200, 20, info.Label, false, false);
|
||||
}
|
||||
|
||||
AddHtmlLocalized(55, 340, 100, 20, 1011447); // BACK
|
||||
AddButton(20, 340, 4005, 4007, 0, GumpButtonType.Page, 1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Commander Options
|
||||
|
||||
if (faction.IsCommander(from))
|
||||
{
|
||||
#region General
|
||||
|
||||
AddPage(6);
|
||||
|
||||
AddHtmlLocalized(20, 30, 200, 20, 1011461); // COMMANDER OPTIONS
|
||||
|
||||
AddHtmlLocalized(20, 70, 120, 20, 1011457); // Tithe rate :
|
||||
if (faction.Tithe >= 0 && faction.Tithe <= 100 && faction.Tithe % 10 == 0)
|
||||
AddHtmlLocalized(140, 70, 250, 20, 1011480 + faction.Tithe / 10);
|
||||
else
|
||||
AddHtml(140, 70, 250, 20, faction.Tithe + "%");
|
||||
|
||||
AddHtmlLocalized(20, 100, 120, 20, 1011474); // Silver available :
|
||||
AddHtml(140, 100, 50, 20, faction.Silver.ToString("N0")); // NOTE: Added 'N0' formatting
|
||||
|
||||
AddHtmlLocalized(55, 130, 200, 20, 1011478); // CHANGE TITHE RATE
|
||||
AddButton(20, 130, 4005, 4007, 0, GumpButtonType.Page, 8);
|
||||
|
||||
AddHtmlLocalized(55, 160, 200, 20, 1018301); // TRANSFER SILVER
|
||||
if (faction.Silver >= 10000)
|
||||
AddButton(20, 160, 4005, 4007, 0, GumpButtonType.Page, 7);
|
||||
else
|
||||
AddImage(20, 160, 4020);
|
||||
|
||||
AddHtmlLocalized(55, 310, 100, 20, 1011447); // BACK
|
||||
AddButton(20, 310, 4005, 4007, 0, GumpButtonType.Page, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Town Finance
|
||||
|
||||
if (faction.Silver >= 10000)
|
||||
{
|
||||
AddPage(7);
|
||||
|
||||
AddHtmlLocalized(20, 30, 250, 20, 1011476); // TOWN FINANCE
|
||||
|
||||
AddHtmlLocalized(20, 50, 400, 20, 1011477); // Select a town to transfer 10000 silver to
|
||||
|
||||
for (int i = 0; i < towns.Count; ++i)
|
||||
{
|
||||
Town town = towns[i];
|
||||
|
||||
AddHtmlText(55, 75 + i * 30, 200, 20, town.Definition.TownName, false, false);
|
||||
|
||||
if (town.Owner == faction)
|
||||
AddButton(20, 75 + i * 30, 4005, 4007, ToButtonID(2, i));
|
||||
else
|
||||
AddImage(20, 75 + i * 30, 4020);
|
||||
}
|
||||
|
||||
AddHtmlLocalized(55, 310, 100, 20, 1011447); // BACK
|
||||
AddButton(20, 310, 4005, 4007, 0, GumpButtonType.Page, 1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Change Tithe Rate
|
||||
|
||||
AddPage(8);
|
||||
|
||||
AddHtmlLocalized(20, 30, 400, 20, 1011479); // Select the % for the new tithe rate
|
||||
|
||||
int y = 55;
|
||||
|
||||
for (int i = 0; i <= 10; ++i)
|
||||
{
|
||||
if (i == 5)
|
||||
y += 5;
|
||||
|
||||
AddHtmlLocalized(55, y, 300, 20, 1011480 + i);
|
||||
AddButton(20, y, 4005, 4007, ToButtonID(3, i));
|
||||
|
||||
y += 20;
|
||||
|
||||
if (i == 5)
|
||||
y += 5;
|
||||
}
|
||||
|
||||
AddHtmlLocalized(55, 310, 300, 20, 1011447); // BACK
|
||||
AddButton(20, 310, 4005, 4007, 0, GumpButtonType.Page, 1);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public override int ButtonTypes => 4;
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (!FromButtonID(info.ButtonID, out int type, out int index))
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0: // general
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: // vote
|
||||
{
|
||||
m_From.SendGump(new ElectionGump(m_From, m_Faction.Election));
|
||||
break;
|
||||
}
|
||||
case 1: // leave
|
||||
{
|
||||
m_From.SendGump(new LeaveFactionGump(m_From, m_Faction));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 1: // merchant title
|
||||
{
|
||||
if (index >= 0 && index <= MerchantTitles.Info.Length)
|
||||
{
|
||||
PlayerState pl = PlayerState.Find(m_From);
|
||||
|
||||
MerchantTitle newTitle = (MerchantTitle)index;
|
||||
MerchantTitleInfo mti = MerchantTitles.GetInfo(newTitle);
|
||||
|
||||
if (mti == null)
|
||||
{
|
||||
m_From.SendLocalizedMessage(1010120); // Your merchant title has been removed
|
||||
|
||||
if (pl != null)
|
||||
pl.MerchantTitle = newTitle;
|
||||
}
|
||||
else if (MerchantTitles.IsQualified(m_From, mti))
|
||||
{
|
||||
m_From.SendLocalizedMessage(mti.Assigned);
|
||||
|
||||
if (pl != null)
|
||||
pl.MerchantTitle = newTitle;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: // transfer silver
|
||||
{
|
||||
if (!m_Faction.IsCommander(m_From))
|
||||
return;
|
||||
|
||||
List<Town> towns = Town.Towns;
|
||||
|
||||
if (index >= 0 && index < towns.Count)
|
||||
{
|
||||
Town town = towns[index];
|
||||
|
||||
if (town.Owner == m_Faction)
|
||||
if (m_Faction.Silver >= 10000)
|
||||
{
|
||||
m_Faction.Silver -= 10000;
|
||||
town.Silver += 10000;
|
||||
|
||||
// 10k in silver has been received by:
|
||||
m_From.SendLocalizedMessage(1042726, true, " " + town.Definition.FriendlyName);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 3: // change tithe
|
||||
{
|
||||
if (!m_Faction.IsCommander(m_From))
|
||||
return;
|
||||
|
||||
if (index >= 0 && index <= 10)
|
||||
m_Faction.Tithe = index * 10;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
292
Projects/Scripts/Engines/Factions/Gumps/FinanceGump.cs
Normal file
292
Projects/Scripts/Engines/Factions/Gumps/FinanceGump.cs
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Multis;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FinanceGump : FactionGump
|
||||
{
|
||||
private static int[] m_PriceOffsets =
|
||||
{
|
||||
-30, -25, -20, -15, -10, -5,
|
||||
+50, +100, +150, +200, +250, +300
|
||||
};
|
||||
|
||||
private Faction m_Faction;
|
||||
private PlayerMobile m_From;
|
||||
private Town m_Town;
|
||||
|
||||
public FinanceGump(PlayerMobile from, Faction faction, Town town) : base(50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Faction = faction;
|
||||
m_Town = town;
|
||||
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 320, 410, 5054);
|
||||
AddBackground(10, 10, 300, 390, 3000);
|
||||
|
||||
#region General
|
||||
|
||||
AddPage(1);
|
||||
|
||||
AddHtmlLocalized(20, 30, 260, 25, 1011541); // FINANCE MINISTER
|
||||
|
||||
|
||||
AddHtmlLocalized(55, 90, 200, 25, 1011539); // CHANGE PRICES
|
||||
AddButton(20, 90, 4005, 4007, 0, GumpButtonType.Page, 2);
|
||||
|
||||
AddHtmlLocalized(55, 120, 200, 25, 1011540); // BUY SHOPKEEPERS
|
||||
AddButton(20, 120, 4005, 4007, 0, GumpButtonType.Page, 3);
|
||||
|
||||
AddHtmlLocalized(55, 150, 200, 25, 1011495); // VIEW FINANCES
|
||||
AddButton(20, 150, 4005, 4007, 0, GumpButtonType.Page, 4);
|
||||
|
||||
AddHtmlLocalized(55, 360, 200, 25, 1011441); // EXIT
|
||||
AddButton(20, 360, 4005, 4007, 0);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Change Prices
|
||||
|
||||
AddPage(2);
|
||||
|
||||
AddHtmlLocalized(20, 30, 200, 25, 1011539); // CHANGE PRICES
|
||||
|
||||
for (int i = 0; i < m_PriceOffsets.Length; ++i)
|
||||
{
|
||||
int ofs = m_PriceOffsets[i];
|
||||
|
||||
int x = 20 + i / 6 * 150;
|
||||
int y = 90 + i % 6 * 30;
|
||||
|
||||
AddRadio(x, y, 208, 209, town.Tax == ofs, i + 1);
|
||||
|
||||
if (ofs < 0)
|
||||
AddLabel(x + 35, y, 0x26, string.Concat("- ", -ofs, "%"));
|
||||
else
|
||||
AddLabel(x + 35, y, 0x12A, string.Concat("+ ", ofs, "%"));
|
||||
}
|
||||
|
||||
AddRadio(20, 270, 208, 209, town.Tax == 0, 0);
|
||||
AddHtmlLocalized(55, 270, 90, 25, 1011542); // normal
|
||||
|
||||
AddHtmlLocalized(55, 330, 200, 25, 1011509); // Set Prices
|
||||
AddButton(20, 330, 4005, 4007, ToButtonID(0, 0));
|
||||
|
||||
AddHtmlLocalized(55, 360, 200, 25, 1011067); // Previous page
|
||||
AddButton(20, 360, 4005, 4007, 0, GumpButtonType.Page, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Buy Shopkeepers
|
||||
|
||||
AddPage(3);
|
||||
|
||||
AddHtmlLocalized(20, 30, 200, 25, 1011540); // BUY SHOPKEEPERS
|
||||
|
||||
List<VendorList> vendorLists = town.VendorLists;
|
||||
|
||||
for (int i = 0; i < vendorLists.Count; ++i)
|
||||
{
|
||||
VendorList list = vendorLists[i];
|
||||
|
||||
AddButton(20, 90 + i * 40, 4005, 4007, 0, GumpButtonType.Page, 5 + i);
|
||||
AddItem(55, 90 + i * 40, list.Definition.ItemID);
|
||||
AddHtmlText(100, 90 + i * 40, 200, 25, list.Definition.Label, false, false);
|
||||
}
|
||||
|
||||
AddHtmlLocalized(55, 360, 200, 25, 1011067); // Previous page
|
||||
AddButton(20, 360, 4005, 4007, 0, GumpButtonType.Page, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
#region View Finances
|
||||
|
||||
AddPage(4);
|
||||
|
||||
int financeUpkeep = town.FinanceUpkeep;
|
||||
int sheriffUpkeep = town.SheriffUpkeep;
|
||||
int dailyIncome = town.DailyIncome;
|
||||
int netCashFlow = town.NetCashFlow;
|
||||
|
||||
|
||||
AddHtmlLocalized(20, 30, 300, 25, 1011524); // FINANCE STATEMENT
|
||||
|
||||
AddHtmlLocalized(20, 80, 300, 25, 1011538); // Current total money for town :
|
||||
AddLabel(20, 100, 0x44, town.Silver.ToString());
|
||||
|
||||
AddHtmlLocalized(20, 130, 300, 25, 1011520); // Finance Minister Upkeep :
|
||||
AddLabel(20, 150, 0x44, financeUpkeep.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(20, 180, 300, 25, 1011521); // Sheriff Upkeep :
|
||||
AddLabel(20, 200, 0x44, sheriffUpkeep.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(20, 230, 300, 25, 1011522); // Town Income :
|
||||
AddLabel(20, 250, 0x44, dailyIncome.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(20, 280, 300, 25, 1011523); // Net Cash flow per day :
|
||||
AddLabel(20, 300, 0x44, netCashFlow.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(55, 360, 200, 25, 1011067); // Previous page
|
||||
AddButton(20, 360, 4005, 4007, 0, GumpButtonType.Page, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Shopkeeper Pages
|
||||
|
||||
for (int i = 0; i < vendorLists.Count; ++i)
|
||||
{
|
||||
VendorList vendorList = vendorLists[i];
|
||||
|
||||
AddPage(5 + i);
|
||||
|
||||
AddHtmlText(60, 30, 300, 25, vendorList.Definition.Header, false, false);
|
||||
AddItem(20, 30, vendorList.Definition.ItemID);
|
||||
|
||||
AddHtmlLocalized(20, 90, 200, 25, 1011514); // You have :
|
||||
AddLabel(230, 90, 0x26, vendorList.Vendors.Count.ToString());
|
||||
|
||||
AddHtmlLocalized(20, 120, 200, 25, 1011515); // Maximum :
|
||||
AddLabel(230, 120, 0x256, vendorList.Definition.Maximum.ToString());
|
||||
|
||||
AddHtmlLocalized(20, 150, 200, 25, 1011516); // Cost :
|
||||
AddLabel(230, 150, 0x44, vendorList.Definition.Price.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(20, 180, 200, 25, 1011517); // Daily Pay :
|
||||
AddLabel(230, 180, 0x37, vendorList.Definition.Upkeep.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(20, 210, 200, 25, 1011518); // Current Silver :
|
||||
AddLabel(230, 210, 0x44, town.Silver.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(20, 240, 200, 25, 1011519); // Current Payroll :
|
||||
AddLabel(230, 240, 0x44, financeUpkeep.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlText(55, 300, 200, 25, vendorList.Definition.Label, false, false);
|
||||
if (town.Silver >= vendorList.Definition.Price)
|
||||
AddButton(20, 300, 4005, 4007, ToButtonID(1, i));
|
||||
else
|
||||
AddImage(20, 300, 4020);
|
||||
|
||||
AddHtmlLocalized(55, 360, 200, 25, 1011067); // Previous page
|
||||
AddButton(20, 360, 4005, 4007, 0, GumpButtonType.Page, 3);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public override int ButtonTypes => 2;
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (!m_Town.IsFinance(m_From) || m_Town.Owner != m_Faction)
|
||||
{
|
||||
m_From.SendLocalizedMessage(1010339); // You no longer control this city
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FromButtonID(info.ButtonID, out int type, out int index))
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0: // general
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: // set price
|
||||
{
|
||||
int[] switches = info.Switches;
|
||||
|
||||
if (switches.Length == 0)
|
||||
break;
|
||||
|
||||
int opt = switches[0];
|
||||
int newTax = 0;
|
||||
|
||||
if (opt >= 1 && opt <= m_PriceOffsets.Length)
|
||||
newTax = m_PriceOffsets[opt - 1];
|
||||
|
||||
if (m_Town.Tax == newTax)
|
||||
break;
|
||||
|
||||
if (m_From.AccessLevel == AccessLevel.Player && !m_Town.TaxChangeReady)
|
||||
{
|
||||
TimeSpan remaining = DateTime.UtcNow - (m_Town.LastTaxChange + Town.TaxChangePeriod);
|
||||
|
||||
if (remaining.TotalMinutes < 4)
|
||||
m_From.SendLocalizedMessage(
|
||||
1042165); // You must wait a short while before changing prices again.
|
||||
else if (remaining.TotalMinutes < 10)
|
||||
m_From.SendLocalizedMessage(
|
||||
1042166); // You must wait several minutes before changing prices again.
|
||||
else if (remaining.TotalHours < 1)
|
||||
m_From.SendLocalizedMessage(
|
||||
1042167); // You must wait up to an hour before changing prices again.
|
||||
else if (remaining.TotalHours < 4)
|
||||
m_From.SendLocalizedMessage(
|
||||
1042168); // You must wait a few hours before changing prices again.
|
||||
else
|
||||
m_From.SendLocalizedMessage(
|
||||
1042169); // You must wait several hours before changing prices again.
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Town.Tax = newTax;
|
||||
|
||||
if (m_From.AccessLevel == AccessLevel.Player)
|
||||
m_Town.LastTaxChange = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 1: // make vendor
|
||||
{
|
||||
List<VendorList> vendorLists = m_Town.VendorLists;
|
||||
|
||||
if (index >= 0 && index < vendorLists.Count)
|
||||
{
|
||||
VendorList vendorList = vendorLists[index];
|
||||
|
||||
if (Town.FromRegion(m_From.Region) != m_Town)
|
||||
{
|
||||
m_From.SendLocalizedMessage(1010305); // You must be in your controlled city to buy Items
|
||||
}
|
||||
else if (vendorList.Vendors.Count >= vendorList.Definition.Maximum)
|
||||
{
|
||||
m_From.SendLocalizedMessage(
|
||||
1010306); // You currently have too many of this enhancement type to place another
|
||||
}
|
||||
else if (BaseBoat.FindBoatAt(m_From.Location, m_From.Map) != null)
|
||||
{
|
||||
m_From.SendMessage("You cannot place a vendor here");
|
||||
}
|
||||
else if (m_Town.Silver >= vendorList.Definition.Price)
|
||||
{
|
||||
BaseFactionVendor vendor = vendorList.Construct(m_Town, m_Faction);
|
||||
|
||||
if (vendor != null)
|
||||
{
|
||||
m_Town.Silver -= vendorList.Definition.Price;
|
||||
|
||||
vendor.MoveToWorld(m_From.Location, m_From.Map);
|
||||
vendor.Home = vendor.Location;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
91
Projects/Scripts/Engines/Factions/Gumps/HorseBreederGump.cs
Normal file
91
Projects/Scripts/Engines/Factions/Gumps/HorseBreederGump.cs
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class HorseBreederGump : FactionGump
|
||||
{
|
||||
private Faction m_Faction;
|
||||
private PlayerMobile m_From;
|
||||
|
||||
public HorseBreederGump(PlayerMobile from, Faction faction) : base(20, 30)
|
||||
{
|
||||
m_From = from;
|
||||
m_Faction = faction;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 320, 280, 5054);
|
||||
AddBackground(10, 10, 300, 260, 3000);
|
||||
|
||||
AddHtmlText(20, 30, 300, 25, faction.Definition.Header, false, false);
|
||||
|
||||
AddHtmlLocalized(20, 60, 300, 25, 1018306); // Purchase a Faction War Horse
|
||||
AddItem(70, 120, 0x3FFE);
|
||||
|
||||
AddItem(150, 120, 0xEF2);
|
||||
AddLabel(190, 122, 0x3E3, FactionWarHorse.SilverPrice.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddItem(150, 150, 0xEEF);
|
||||
AddLabel(190, 152, 0x3E3, FactionWarHorse.GoldPrice.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(55, 210, 200, 25, 1011011); // CONTINUE
|
||||
AddButton(20, 210, 4005, 4007, 1);
|
||||
|
||||
AddHtmlLocalized(55, 240, 200, 25, 1011012); // CANCEL
|
||||
AddButton(20, 240, 4005, 4007, 0);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID != 1)
|
||||
return;
|
||||
|
||||
if (Faction.Find(m_From) != m_Faction)
|
||||
return;
|
||||
|
||||
Container pack = m_From.Backpack;
|
||||
|
||||
if (pack == null)
|
||||
return;
|
||||
|
||||
FactionWarHorse horse = new FactionWarHorse(m_Faction);
|
||||
|
||||
if (m_From.Followers + horse.ControlSlots > m_From.FollowersMax)
|
||||
{
|
||||
// TODO: Message?
|
||||
horse.Delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pack.GetAmount(typeof(Silver)) < FactionWarHorse.SilverPrice)
|
||||
{
|
||||
sender.Mobile.SendLocalizedMessage(1042204); // You do not have enough silver.
|
||||
horse.Delete();
|
||||
}
|
||||
else if (pack.GetAmount(typeof(Gold)) < FactionWarHorse.GoldPrice)
|
||||
{
|
||||
sender.Mobile.SendLocalizedMessage(1042205); // You do not have enough gold.
|
||||
horse.Delete();
|
||||
}
|
||||
else if (pack.ConsumeTotal(typeof(Silver), FactionWarHorse.SilverPrice) &&
|
||||
pack.ConsumeTotal(typeof(Gold), FactionWarHorse.GoldPrice))
|
||||
{
|
||||
horse.Controlled = true;
|
||||
horse.ControlMaster = m_From;
|
||||
|
||||
horse.ControlOrder = OrderType.Follow;
|
||||
horse.ControlTarget = m_From;
|
||||
|
||||
horse.MoveToWorld(m_From.Location, m_From.Map);
|
||||
}
|
||||
else
|
||||
{
|
||||
horse.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
50
Projects/Scripts/Engines/Factions/Gumps/JoinStoneGump.cs
Normal file
50
Projects/Scripts/Engines/Factions/Gumps/JoinStoneGump.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class JoinStoneGump : FactionGump
|
||||
{
|
||||
private Faction m_Faction;
|
||||
private PlayerMobile m_From;
|
||||
|
||||
public JoinStoneGump(PlayerMobile from, Faction faction) : base(20, 30)
|
||||
{
|
||||
m_From = from;
|
||||
m_Faction = faction;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 550, 440, 5054);
|
||||
AddBackground(10, 10, 530, 420, 3000);
|
||||
|
||||
|
||||
AddHtmlText(20, 30, 510, 20, faction.Definition.Header, false, false);
|
||||
AddHtmlText(20, 130, 510, 100, faction.Definition.About, true, true);
|
||||
|
||||
|
||||
AddHtmlLocalized(20, 60, 100, 20, 1011429); // Led By :
|
||||
AddHtml(125, 60, 200, 20, faction.Commander != null ? faction.Commander.Name : "Nobody");
|
||||
|
||||
AddHtmlLocalized(20, 80, 100, 20, 1011457); // Tithe rate :
|
||||
if (faction.Tithe >= 0 && faction.Tithe <= 100 && faction.Tithe % 10 == 0)
|
||||
AddHtmlLocalized(125, 80, 350, 20, 1011480 + faction.Tithe / 10);
|
||||
else
|
||||
AddHtml(125, 80, 350, 20, faction.Tithe + "%");
|
||||
|
||||
|
||||
AddButton(20, 400, 4005, 4007, 1);
|
||||
AddHtmlLocalized(55, 400, 200, 20, 1011425); // JOIN THIS FACTION
|
||||
|
||||
AddButton(300, 400, 4005, 4007, 0);
|
||||
AddHtmlLocalized(335, 400, 200, 20, 1011012); // CANCEL
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID == 1)
|
||||
m_Faction.OnJoinAccepted(m_From);
|
||||
}
|
||||
}
|
||||
}
|
||||
93
Projects/Scripts/Engines/Factions/Gumps/LeaveFactionGump.cs
Normal file
93
Projects/Scripts/Engines/Factions/Gumps/LeaveFactionGump.cs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
using System;
|
||||
using Server.Guilds;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class LeaveFactionGump : FactionGump
|
||||
{
|
||||
private Faction m_Faction;
|
||||
private PlayerMobile m_From;
|
||||
|
||||
public LeaveFactionGump(PlayerMobile from, Faction faction) : base(20, 30)
|
||||
{
|
||||
m_From = from;
|
||||
m_Faction = faction;
|
||||
|
||||
AddBackground(0, 0, 270, 120, 5054);
|
||||
AddBackground(10, 10, 250, 100, 3000);
|
||||
|
||||
if (from.Guild is Guild guild && guild.Leader == from)
|
||||
AddHtmlLocalized(20, 15, 230, 60, 1018057, true,
|
||||
true); // Are you sure you want your entire guild to leave this faction?
|
||||
else
|
||||
AddHtmlLocalized(20, 15, 230, 60, 1018063, true, true); // Are you sure you want to leave this faction?
|
||||
|
||||
AddHtmlLocalized(55, 80, 75, 20, 1011011); // CONTINUE
|
||||
AddButton(20, 80, 4005, 4007, 1);
|
||||
|
||||
AddHtmlLocalized(170, 80, 75, 20, 1011012); // CANCEL
|
||||
AddButton(135, 80, 4005, 4007, 2);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
switch (info.ButtonID)
|
||||
{
|
||||
case 1: // continue
|
||||
{
|
||||
if (!(m_From.Guild is Guild guild))
|
||||
{
|
||||
PlayerState pl = PlayerState.Find(m_From);
|
||||
|
||||
if (pl != null)
|
||||
{
|
||||
pl.Leaving = DateTime.UtcNow;
|
||||
|
||||
if (Faction.LeavePeriod == TimeSpan.FromDays(3.0))
|
||||
m_From.SendLocalizedMessage(1005065); // You will be removed from the faction in 3 days
|
||||
else
|
||||
m_From.SendMessage("You will be removed from the faction in {0} days.",
|
||||
Faction.LeavePeriod.TotalDays);
|
||||
}
|
||||
}
|
||||
else if (guild.Leader != m_From)
|
||||
{
|
||||
m_From.SendLocalizedMessage(
|
||||
1005061); // You cannot quit the faction because you are not the guild master
|
||||
}
|
||||
else
|
||||
{
|
||||
m_From.SendLocalizedMessage(1042285); // Your guild is now quitting the faction.
|
||||
|
||||
for (int i = 0; i < guild.Members.Count; ++i)
|
||||
{
|
||||
Mobile mob = guild.Members[i];
|
||||
PlayerState pl = PlayerState.Find(mob);
|
||||
|
||||
if (pl != null)
|
||||
{
|
||||
pl.Leaving = DateTime.UtcNow;
|
||||
|
||||
if (Faction.LeavePeriod == TimeSpan.FromDays(3.0))
|
||||
mob.SendLocalizedMessage(1005060); // Your guild will quit the faction in 3 days
|
||||
else
|
||||
mob.SendMessage("Your guild will quit the faction in {0} days.",
|
||||
Faction.LeavePeriod.TotalDays);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: // cancel
|
||||
{
|
||||
m_From.SendLocalizedMessage(500737); // Canceled resignation.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
188
Projects/Scripts/Engines/Factions/Gumps/SheriffGump.cs
Normal file
188
Projects/Scripts/Engines/Factions/Gumps/SheriffGump.cs
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Multis;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class SheriffGump : FactionGump
|
||||
{
|
||||
private Faction m_Faction;
|
||||
private PlayerMobile m_From;
|
||||
private Town m_Town;
|
||||
|
||||
public SheriffGump(PlayerMobile from, Faction faction, Town town) : base(50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Faction = faction;
|
||||
m_Town = town;
|
||||
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 320, 410, 5054);
|
||||
AddBackground(10, 10, 300, 390, 3000);
|
||||
|
||||
#region General
|
||||
|
||||
AddPage(1);
|
||||
|
||||
AddHtmlLocalized(20, 30, 260, 25, 1011431); // Sheriff
|
||||
|
||||
AddHtmlLocalized(55, 90, 200, 25, 1011494); // HIRE GUARDS
|
||||
AddButton(20, 90, 4005, 4007, 0, GumpButtonType.Page, 3);
|
||||
|
||||
AddHtmlLocalized(55, 120, 200, 25, 1011495); // VIEW FINANCES
|
||||
AddButton(20, 120, 4005, 4007, 0, GumpButtonType.Page, 2);
|
||||
|
||||
AddHtmlLocalized(55, 360, 200, 25, 1011441); // Exit
|
||||
AddButton(20, 360, 4005, 4007, 0);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Finances
|
||||
|
||||
AddPage(2);
|
||||
|
||||
int financeUpkeep = town.FinanceUpkeep;
|
||||
int sheriffUpkeep = town.SheriffUpkeep;
|
||||
int dailyIncome = town.DailyIncome;
|
||||
int netCashFlow = town.NetCashFlow;
|
||||
|
||||
AddHtmlLocalized(20, 30, 300, 25, 1011524); // FINANCE STATEMENT
|
||||
|
||||
AddHtmlLocalized(20, 80, 300, 25, 1011538); // Current total money for town :
|
||||
AddLabel(20, 100, 0x44, town.Silver.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(20, 130, 300, 25, 1011520); // Finance Minister Upkeep :
|
||||
AddLabel(20, 150, 0x44, financeUpkeep.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(20, 180, 300, 25, 1011521); // Sheriff Upkeep :
|
||||
AddLabel(20, 200, 0x44, sheriffUpkeep.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(20, 230, 300, 25, 1011522); // Town Income :
|
||||
AddLabel(20, 250, 0x44, dailyIncome.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(20, 280, 300, 25, 1011523); // Net Cash flow per day :
|
||||
AddLabel(20, 300, 0x44, netCashFlow.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(55, 360, 200, 25, 1011067); // Previous page
|
||||
AddButton(20, 360, 4005, 4007, 0, GumpButtonType.Page, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Hire Guards
|
||||
|
||||
AddPage(3);
|
||||
|
||||
AddHtmlLocalized(20, 30, 300, 25, 1011494); // HIRE GUARDS
|
||||
|
||||
List<GuardList> guardLists = town.GuardLists;
|
||||
|
||||
for (int i = 0; i < guardLists.Count; ++i)
|
||||
{
|
||||
GuardList guardList = guardLists[i];
|
||||
int y = 90 + i * 60;
|
||||
|
||||
AddButton(20, y, 4005, 4007, 0, GumpButtonType.Page, 4 + i);
|
||||
CenterItem(guardList.Definition.ItemID, 50, y - 20, 70, 60);
|
||||
AddHtmlText(120, y, 200, 25, guardList.Definition.Header, false, false);
|
||||
}
|
||||
|
||||
AddHtmlLocalized(55, 360, 200, 25, 1011067); // Previous page
|
||||
AddButton(20, 360, 4005, 4007, 0, GumpButtonType.Page, 1);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Guard Pages
|
||||
|
||||
for (int i = 0; i < guardLists.Count; ++i)
|
||||
{
|
||||
GuardList guardList = guardLists[i];
|
||||
|
||||
AddPage(4 + i);
|
||||
|
||||
AddHtmlText(90, 30, 300, 25, guardList.Definition.Header, false, false);
|
||||
CenterItem(guardList.Definition.ItemID, 10, 10, 80, 80);
|
||||
|
||||
AddHtmlLocalized(20, 90, 200, 25, 1011514); // You have :
|
||||
AddLabel(230, 90, 0x26, guardList.Guards.Count.ToString());
|
||||
|
||||
AddHtmlLocalized(20, 120, 200, 25, 1011515); // Maximum :
|
||||
AddLabel(230, 120, 0x12A, guardList.Definition.Maximum.ToString());
|
||||
|
||||
AddHtmlLocalized(20, 150, 200, 25, 1011516); // Cost :
|
||||
AddLabel(230, 150, 0x44, guardList.Definition.Price.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(20, 180, 200, 25, 1011517); // Daily Pay :
|
||||
AddLabel(230, 180, 0x37, guardList.Definition.Upkeep.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(20, 210, 200, 25, 1011518); // Current Silver :
|
||||
AddLabel(230, 210, 0x44, town.Silver.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlLocalized(20, 240, 200, 25, 1011519); // Current Payroll :
|
||||
AddLabel(230, 240, 0x44, sheriffUpkeep.ToString("N0")); // NOTE: Added 'N0'
|
||||
|
||||
AddHtmlText(55, 300, 200, 25, guardList.Definition.Label, false, false);
|
||||
AddButton(20, 300, 4005, 4007, 1 + i);
|
||||
|
||||
AddHtmlLocalized(55, 360, 200, 25, 1011067); // Previous page
|
||||
AddButton(20, 360, 4005, 4007, 0, GumpButtonType.Page, 3);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
private void CenterItem(int itemID, int x, int y, int w, int h)
|
||||
{
|
||||
Rectangle2D rc = ItemBounds.Table[itemID];
|
||||
AddItem(x + (w - rc.Width) / 2 - rc.X, y + (h - rc.Height) / 2 - rc.Y, itemID);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (!m_Town.IsSheriff(m_From) || m_Town.Owner != m_Faction)
|
||||
{
|
||||
m_From.SendLocalizedMessage(1010339); // You no longer control this city
|
||||
return;
|
||||
}
|
||||
|
||||
int index = info.ButtonID - 1;
|
||||
|
||||
if (index >= 0 && index < m_Town.GuardLists.Count)
|
||||
{
|
||||
GuardList guardList = m_Town.GuardLists[index];
|
||||
|
||||
if (Town.FromRegion(m_From.Region) != m_Town)
|
||||
{
|
||||
m_From.SendLocalizedMessage(1010305); // You must be in your controlled city to buy Items
|
||||
}
|
||||
else if (guardList.Guards.Count >= guardList.Definition.Maximum)
|
||||
{
|
||||
m_From.SendLocalizedMessage(
|
||||
1010306); // You currently have too many of this enhancement type to place another
|
||||
}
|
||||
else if (BaseBoat.FindBoatAt(m_From.Location, m_From.Map) != null)
|
||||
{
|
||||
m_From.SendMessage("You cannot place a guard here");
|
||||
}
|
||||
else if (m_Town.Silver >= guardList.Definition.Price)
|
||||
{
|
||||
BaseFactionGuard guard = guardList.Construct();
|
||||
|
||||
if (guard != null)
|
||||
{
|
||||
guard.Faction = m_Faction;
|
||||
guard.Town = m_Town;
|
||||
|
||||
m_Town.Silver -= guardList.Definition.Price;
|
||||
|
||||
guard.MoveToWorld(m_From.Location, m_From.Map);
|
||||
guard.Home = guard.Location;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
204
Projects/Scripts/Engines/Factions/Gumps/TownStoneGump.cs
Normal file
204
Projects/Scripts/Engines/Factions/Gumps/TownStoneGump.cs
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class TownStoneGump : FactionGump
|
||||
{
|
||||
private Faction m_Faction;
|
||||
private PlayerMobile m_From;
|
||||
private Town m_Town;
|
||||
|
||||
public TownStoneGump(PlayerMobile from, Faction faction, Town town) : base(50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Faction = faction;
|
||||
m_Town = town;
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 320, 250, 5054);
|
||||
AddBackground(10, 10, 300, 230, 3000);
|
||||
|
||||
AddHtmlText(25, 30, 250, 25, town.Definition.TownStoneHeader, false, false);
|
||||
|
||||
AddHtmlLocalized(55, 60, 150, 25, 1011557); // Hire Sheriff
|
||||
AddButton(20, 60, 4005, 4007, 1);
|
||||
|
||||
AddHtmlLocalized(55, 90, 150, 25, 1011559); // Hire Finance Minister
|
||||
AddButton(20, 90, 4005, 4007, 2);
|
||||
|
||||
AddHtmlLocalized(55, 120, 150, 25, 1011558); // Fire Sheriff
|
||||
AddButton(20, 120, 4005, 4007, 3);
|
||||
|
||||
AddHtmlLocalized(55, 150, 150, 25, 1011560); // Fire Finance Minister
|
||||
AddButton(20, 150, 4005, 4007, 4);
|
||||
|
||||
AddHtmlLocalized(55, 210, 150, 25, 1011441); // EXIT
|
||||
AddButton(20, 210, 4005, 4007, 0);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (m_Town.Owner != m_Faction || !m_Faction.IsCommander(m_From))
|
||||
{
|
||||
m_From.SendLocalizedMessage(1010339); // You no longer control this city
|
||||
return;
|
||||
}
|
||||
|
||||
switch (info.ButtonID)
|
||||
{
|
||||
case 1: // hire sheriff
|
||||
{
|
||||
if (m_Town.Sheriff != null)
|
||||
{
|
||||
m_From.SendLocalizedMessage(1010342); // You must fire your Sheriff before you can elect a new one
|
||||
}
|
||||
else
|
||||
{
|
||||
m_From.SendLocalizedMessage(1010347); // Who shall be your new sheriff
|
||||
m_From.BeginTarget(12, false, TargetFlags.None, HireSheriff_OnTarget);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: // hire finance minister
|
||||
{
|
||||
if (m_Town.Finance != null)
|
||||
{
|
||||
m_From.SendLocalizedMessage(
|
||||
1010345); // You must fire your finance minister before you can elect a new one
|
||||
}
|
||||
else
|
||||
{
|
||||
m_From.SendLocalizedMessage(1010348); // Who shall be your new Minister of Finances?
|
||||
m_From.BeginTarget(12, false, TargetFlags.None, HireFinanceMinister_OnTarget);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 3: // fire sheriff
|
||||
{
|
||||
if (m_Town.Sheriff == null)
|
||||
{
|
||||
m_From.SendLocalizedMessage(1010350); // You need to elect a sheriff before you can fire one
|
||||
}
|
||||
else
|
||||
{
|
||||
m_From.SendLocalizedMessage(1010349); // You have fired your sheriff
|
||||
m_Town.Sheriff.SendLocalizedMessage(1010270); // You have been fired as Sheriff
|
||||
m_Town.Sheriff = null;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 4: // fire finance minister
|
||||
{
|
||||
if (m_Town.Finance == null)
|
||||
{
|
||||
m_From.SendLocalizedMessage(
|
||||
1010352); // You need to elect a financial minister before you can fire one
|
||||
}
|
||||
else
|
||||
{
|
||||
m_From.SendLocalizedMessage(1010351); // You have fired your financial Minister
|
||||
m_Town.Finance.SendLocalizedMessage(1010151); // You have been fired as Finance Minister
|
||||
m_Town.Finance = null;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HireSheriff_OnTarget(Mobile from, object obj)
|
||||
{
|
||||
if (m_Town.Owner != m_Faction || !m_Faction.IsCommander(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1010339); // You no longer control this city
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_Town.Sheriff != null)
|
||||
{
|
||||
from.SendLocalizedMessage(1010342); // You must fire your Sheriff before you can elect a new one
|
||||
}
|
||||
else if (obj is Mobile targ)
|
||||
{
|
||||
PlayerState pl = PlayerState.Find(targ);
|
||||
|
||||
if (pl == null)
|
||||
{
|
||||
from.SendLocalizedMessage(1010337); // You must pick someone in a faction
|
||||
}
|
||||
else if (pl.Faction != m_Faction)
|
||||
{
|
||||
from.SendLocalizedMessage(1010338); // You must pick someone in the correct faction
|
||||
}
|
||||
else if (m_Faction.Commander == targ)
|
||||
{
|
||||
from.SendLocalizedMessage(1010335); // You cannot elect a commander to a town position
|
||||
}
|
||||
else if (pl.Sheriff != null || pl.Finance != null)
|
||||
{
|
||||
from.SendLocalizedMessage(1005245); // You must pick someone who does not already hold a city post
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Town.Sheriff = targ;
|
||||
targ.SendLocalizedMessage(1010340); // You are now the Sheriff
|
||||
from.SendLocalizedMessage(1010341); // You have elected a Sheriff
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(1010334); // You must select a player to hold a city position!
|
||||
}
|
||||
}
|
||||
|
||||
private void HireFinanceMinister_OnTarget(Mobile from, object obj)
|
||||
{
|
||||
if (m_Town.Owner != m_Faction || !m_Faction.IsCommander(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1010339); // You no longer control this city
|
||||
}
|
||||
else if (m_Town.Finance != null)
|
||||
{
|
||||
from.SendLocalizedMessage(1010342); // You must fire your Sheriff before you can elect a new one
|
||||
}
|
||||
else if (obj is Mobile targ)
|
||||
{
|
||||
PlayerState pl = PlayerState.Find(targ);
|
||||
|
||||
if (pl == null)
|
||||
{
|
||||
from.SendLocalizedMessage(1010337); // You must pick someone in a faction
|
||||
}
|
||||
else if (pl.Faction != m_Faction)
|
||||
{
|
||||
from.SendLocalizedMessage(1010338); // You must pick someone in the correct faction
|
||||
}
|
||||
else if (m_Faction.Commander == targ)
|
||||
{
|
||||
from.SendLocalizedMessage(1010335); // You cannot elect a commander to a town position
|
||||
}
|
||||
else if (pl.Sheriff != null || pl.Finance != null)
|
||||
{
|
||||
from.SendLocalizedMessage(1005245); // You must pick someone who does not already hold a city post
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Town.Finance = targ;
|
||||
targ.SendLocalizedMessage(1010343); // You are now the Financial Minister
|
||||
from.SendLocalizedMessage(1010344); // You have elected a Financial Minister
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(1010334); // You must select a player to hold a city position!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
Projects/Scripts/Engines/Factions/Gumps/VoteGump.cs
Normal file
66
Projects/Scripts/Engines/Factions/Gumps/VoteGump.cs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
using Server.Gumps;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class VoteGump : FactionGump
|
||||
{
|
||||
private Election m_Election;
|
||||
private PlayerMobile m_From;
|
||||
|
||||
public VoteGump(PlayerMobile from, Election election) : base(50, 50)
|
||||
{
|
||||
m_From = from;
|
||||
m_Election = election;
|
||||
|
||||
bool canVote = election.CanVote(from);
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 420, 350, 5054);
|
||||
AddBackground(10, 10, 400, 330, 3000);
|
||||
|
||||
AddHtmlText(20, 20, 380, 20, election.Faction.Definition.Header, false, false);
|
||||
|
||||
if (canVote)
|
||||
AddHtmlLocalized(20, 60, 380, 20, 1011428); // VOTE FOR LEADERSHIP
|
||||
else
|
||||
AddHtmlLocalized(20, 60, 380, 20, 1038032); // You have already voted in this election.
|
||||
|
||||
for (int i = 0; i < election.Candidates.Count; ++i)
|
||||
{
|
||||
Candidate cd = election.Candidates[i];
|
||||
|
||||
if (canVote)
|
||||
AddButton(20, 100 + i * 20, 4005, 4007, i + 1);
|
||||
|
||||
AddLabel(55, 100 + i * 20, 0, cd.Mobile.Name);
|
||||
AddLabel(300, 100 + i * 20, 0, cd.Votes.ToString());
|
||||
}
|
||||
|
||||
AddButton(20, 310, 4005, 4007, 0);
|
||||
AddHtmlLocalized(55, 310, 100, 20, 1011012); // CANCEL
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (info.ButtonID == 0)
|
||||
{
|
||||
m_From.SendGump(new FactionStoneGump(m_From, m_Election.Faction));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_Election.CanVote(m_From))
|
||||
return;
|
||||
|
||||
int index = info.ButtonID - 1;
|
||||
|
||||
if (index >= 0 && index < m_Election.Candidates.Count)
|
||||
m_Election.Candidates[index].Voters.Add(new Voter(m_From, m_Election.Candidates[index].Mobile));
|
||||
|
||||
m_From.SendGump(new VoteGump(m_From, m_Election));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class CouncilOfMages : Faction
|
||||
{
|
||||
public CouncilOfMages()
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
Definition =
|
||||
new FactionDefinition(
|
||||
1,
|
||||
1325, // blue
|
||||
1310, // bluish white
|
||||
1325, // join stone : blue
|
||||
1325, // broadcast : blue
|
||||
0x77, 0x3EB1, // war horse
|
||||
"Council of Mages", "council", "CoM",
|
||||
new TextDefinition(1011535, "COUNCIL OF MAGES"),
|
||||
new TextDefinition(1060770, "Council of Mages faction"),
|
||||
new TextDefinition(1011422, "<center>COUNCIL OF MAGES</center>"),
|
||||
new TextDefinition(1011449,
|
||||
"The council of Mages have their roots in the city of Moonglow, where " +
|
||||
"they once convened. They began as a small movement, dedicated to " +
|
||||
"calling forth the Stranger, who saved the lands once before. A " +
|
||||
"series of war and murders and misbegotten trials by those loyal to " +
|
||||
"Lord British has caused the group to take up the banner of war."),
|
||||
new TextDefinition(1011455, "This city is controlled by the Council of Mages."),
|
||||
new TextDefinition(1042253, "This sigil has been corrupted by the Council of Mages"),
|
||||
new TextDefinition(1041044, "The faction signup stone for the Council of Mages"),
|
||||
new TextDefinition(1041382, "The Faction Stone of the Council of Mages"),
|
||||
new TextDefinition(1011464, ": Council of Mages"),
|
||||
new TextDefinition(1005187, "Members of the Council of Mages will now be ignored."),
|
||||
new TextDefinition(1005188, "Members of the Council of Mages will now be warned to leave."),
|
||||
new TextDefinition(1005189, "Members of the Council of Mages will now be beaten with a stick."),
|
||||
// Moonglow
|
||||
new StrongholdDefinition(
|
||||
new[]
|
||||
{
|
||||
new Rectangle2D(4463, 1487, 15, 35),
|
||||
new Rectangle2D(4450, 1522, 35, 48)
|
||||
},
|
||||
new Point3D(4469, 1486, 0),
|
||||
new Point3D(4457, 1544, 0),
|
||||
new[]
|
||||
{
|
||||
new Point3D(4464, 1534, 21),
|
||||
new Point3D(4470, 1536, 21),
|
||||
new Point3D(4468, 1534, 21),
|
||||
new Point3D(4470, 1534, 21),
|
||||
new Point3D(4468, 1536, 21),
|
||||
new Point3D(4466, 1534, 21),
|
||||
new Point3D(4466, 1536, 21),
|
||||
new Point3D(4464, 1536, 21)
|
||||
}),
|
||||
// Magincia
|
||||
/* new StrongholdDefinition(
|
||||
new Rectangle2D[]
|
||||
{
|
||||
new Rectangle2D( 3756, 2232, 4, 23 ),
|
||||
new Rectangle2D( 3760, 2227, 60, 28 ),
|
||||
new Rectangle2D( 3782, 2219, 18, 8 ),
|
||||
new Rectangle2D( 3778, 2255, 35, 17 )
|
||||
},
|
||||
new Point3D( 3750, 2241, 20 ),
|
||||
new Point3D( 3795, 2259, 20 ),
|
||||
new Point3D[]
|
||||
{
|
||||
new Point3D( 3793, 2255, 20 ),
|
||||
new Point3D( 3793, 2252, 20 ),
|
||||
new Point3D( 3793, 2249, 20 ),
|
||||
new Point3D( 3793, 2246, 20 ),
|
||||
new Point3D( 3797, 2255, 20 ),
|
||||
new Point3D( 3797, 2252, 20 ),
|
||||
new Point3D( 3797, 2249, 20 ),
|
||||
new Point3D( 3797, 2246, 20 )
|
||||
} ), */
|
||||
new[]
|
||||
{
|
||||
new RankDefinition(10, 991, 8, new TextDefinition(1060789, "Inquisitor of the Council")),
|
||||
new RankDefinition(9, 950, 7, new TextDefinition(1060788, "Archon of Principle")),
|
||||
new RankDefinition(8, 900, 6, new TextDefinition(1060787, "Luminary")),
|
||||
new RankDefinition(7, 800, 6, new TextDefinition(1060787, "Luminary")),
|
||||
new RankDefinition(6, 700, 5, new TextDefinition(1060786, "Diviner")),
|
||||
new RankDefinition(5, 600, 5, new TextDefinition(1060786, "Diviner")),
|
||||
new RankDefinition(4, 500, 5, new TextDefinition(1060786, "Diviner")),
|
||||
new RankDefinition(3, 400, 4, new TextDefinition(1060785, "Mystic")),
|
||||
new RankDefinition(2, 200, 4, new TextDefinition(1060785, "Mystic")),
|
||||
new RankDefinition(1, 0, 4, new TextDefinition(1060785, "Mystic"))
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new GuardDefinition(typeof(FactionHenchman), 0x1403, 5000, 1000, 10,
|
||||
new TextDefinition(1011526, "HENCHMAN"), new TextDefinition(1011510, "Hire Henchman")),
|
||||
new GuardDefinition(typeof(FactionMercenary), 0x0F62, 6000, 2000, 10,
|
||||
new TextDefinition(1011527, "MERCENARY"), new TextDefinition(1011511, "Hire Mercenary")),
|
||||
new GuardDefinition(typeof(FactionSorceress), 0x0E89, 7000, 3000, 10,
|
||||
new TextDefinition(1011507, "SORCERESS"), new TextDefinition(1011501, "Hire Sorceress")),
|
||||
new GuardDefinition(typeof(FactionWizard), 0x13F8, 8000, 4000, 10,
|
||||
new TextDefinition(1011508, "ELDER WIZARD"), new TextDefinition(1011502, "Hire Elder Wizard"))
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static Faction Instance{ get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class Minax : Faction
|
||||
{
|
||||
public Minax()
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
Definition =
|
||||
new FactionDefinition(
|
||||
0,
|
||||
1645, // dark red
|
||||
1109, // shadow
|
||||
1645, // join stone : dark red
|
||||
1645, // broadcast : dark red
|
||||
0x78, 0x3EAF, // war horse
|
||||
"Minax", "minax", "Min",
|
||||
new TextDefinition(1011534, "MINAX"),
|
||||
new TextDefinition(1060769, "Minax faction"),
|
||||
new TextDefinition(1011421, "<center>FOLLOWERS OF MINAX</center>"),
|
||||
new TextDefinition(1011448,
|
||||
"The followers of Minax have taken control in the old lands, " +
|
||||
"and intend to hold it for as long as they can. Allying themselves " +
|
||||
"with orcs, headless, gazers, trolls, and other beasts, they seek " +
|
||||
"revenge against Lord British, for slights both real and imagined, " +
|
||||
"though some of the followers wish only to wreak havoc on the " +
|
||||
"unsuspecting populace."),
|
||||
new TextDefinition(1011453, "This city is controlled by Minax."),
|
||||
new TextDefinition(1042252, "This sigil has been corrupted by the Followers of Minax"),
|
||||
new TextDefinition(1041043, "The faction signup stone for the Followers of Minax"),
|
||||
new TextDefinition(1041381, "The Faction Stone of Minax"),
|
||||
new TextDefinition(1011463, ": Minax"),
|
||||
new TextDefinition(1005190, "Followers of Minax will now be ignored."),
|
||||
new TextDefinition(1005191, "Followers of Minax will now be told to go away."),
|
||||
new TextDefinition(1005192, "Followers of Minax will now be hanged by their toes."),
|
||||
new StrongholdDefinition(
|
||||
new[]
|
||||
{
|
||||
new Rectangle2D(1097, 2570, 70, 50)
|
||||
},
|
||||
new Point3D(1172, 2593, 0),
|
||||
new Point3D(1117, 2587, 18),
|
||||
new[]
|
||||
{
|
||||
new Point3D(1113, 2601, 18),
|
||||
new Point3D(1113, 2598, 18),
|
||||
new Point3D(1113, 2595, 18),
|
||||
new Point3D(1113, 2592, 18),
|
||||
new Point3D(1116, 2601, 18),
|
||||
new Point3D(1116, 2598, 18),
|
||||
new Point3D(1116, 2595, 18),
|
||||
new Point3D(1116, 2592, 18)
|
||||
}),
|
||||
new[]
|
||||
{
|
||||
new RankDefinition(10, 991, 8, new TextDefinition(1060784, "Avenger of Mondain")),
|
||||
new RankDefinition(9, 950, 7, new TextDefinition(1060783, "Dread Knight")),
|
||||
new RankDefinition(8, 900, 6, new TextDefinition(1060782, "Warlord")),
|
||||
new RankDefinition(7, 800, 6, new TextDefinition(1060782, "Warlord")),
|
||||
new RankDefinition(6, 700, 5, new TextDefinition(1060781, "Executioner")),
|
||||
new RankDefinition(5, 600, 5, new TextDefinition(1060781, "Executioner")),
|
||||
new RankDefinition(4, 500, 5, new TextDefinition(1060781, "Executioner")),
|
||||
new RankDefinition(3, 400, 4, new TextDefinition(1060780, "Defiler")),
|
||||
new RankDefinition(2, 200, 4, new TextDefinition(1060780, "Defiler")),
|
||||
new RankDefinition(1, 0, 4, new TextDefinition(1060780, "Defiler"))
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new GuardDefinition(typeof(FactionHenchman), 0x1403, 5000, 1000, 10,
|
||||
new TextDefinition(1011526, "HENCHMAN"), new TextDefinition(1011510, "Hire Henchman")),
|
||||
new GuardDefinition(typeof(FactionMercenary), 0x0F62, 6000, 2000, 10,
|
||||
new TextDefinition(1011527, "MERCENARY"), new TextDefinition(1011511, "Hire Mercenary")),
|
||||
new GuardDefinition(typeof(FactionBerserker), 0x0F4B, 7000, 3000, 10,
|
||||
new TextDefinition(1011505, "BERSERKER"), new TextDefinition(1011499, "Hire Berserker")),
|
||||
new GuardDefinition(typeof(FactionDragoon), 0x1439, 8000, 4000, 10,
|
||||
new TextDefinition(1011506, "DRAGOON"), new TextDefinition(1011500, "Hire Dragoon"))
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static Faction Instance{ get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class Shadowlords : Faction
|
||||
{
|
||||
public Shadowlords()
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
Definition =
|
||||
new FactionDefinition(
|
||||
3,
|
||||
1109, // shadow
|
||||
2211, // green
|
||||
1109, // join stone : shadow
|
||||
2211, // broadcast : green
|
||||
0x79, 0x3EB0, // war horse
|
||||
"Shadowlords", "shadow", "SL",
|
||||
new TextDefinition(1011537, "SHADOWLORDS"),
|
||||
new TextDefinition(1060772, "Shadowlords faction"),
|
||||
new TextDefinition(1011424, "<center>SHADES OF DARKNESS</center>"),
|
||||
new TextDefinition(1011451,
|
||||
"The Shadow Lords are a faction that has sprung up within the ranks of " +
|
||||
"Minax. Comprised mostly of undead and those who would seek to be " +
|
||||
"necromancers, they pose a threat to both the sides of good and evil. " +
|
||||
"Their plans have disrupted the hold Minax has over Felucca, and their " +
|
||||
"ultimate goal is to destroy all life."),
|
||||
new TextDefinition(1011456, "This city is controlled by the Shadow Lords."),
|
||||
new TextDefinition(1042255, "This sigil has been corrupted by the Shadowlords"),
|
||||
new TextDefinition(1041046, "The faction signup stone for the Shadowlords"),
|
||||
new TextDefinition(1041384, "The Faction Stone of the Shadowlords"),
|
||||
new TextDefinition(1011466, ": Shadowlords"),
|
||||
new TextDefinition(1005184, "Minions of the Shadowlords will now be ignored."),
|
||||
new TextDefinition(1005185, "Minions of the Shadowlords will now be warned of their impending deaths."),
|
||||
new TextDefinition(1005186, "Minions of the Shadowlords will now be attacked at will."),
|
||||
new StrongholdDefinition(
|
||||
new[]
|
||||
{
|
||||
new Rectangle2D(960, 688, 8, 9),
|
||||
new Rectangle2D(944, 697, 24, 23)
|
||||
},
|
||||
new Point3D(969, 768, 0),
|
||||
new Point3D(947, 713, 0),
|
||||
new[]
|
||||
{
|
||||
new Point3D(953, 713, 20),
|
||||
new Point3D(953, 709, 20),
|
||||
new Point3D(953, 705, 20),
|
||||
new Point3D(953, 701, 20),
|
||||
new Point3D(957, 713, 20),
|
||||
new Point3D(957, 709, 20),
|
||||
new Point3D(957, 705, 20),
|
||||
new Point3D(957, 701, 20)
|
||||
}),
|
||||
new[]
|
||||
{
|
||||
new RankDefinition(10, 991, 8, new TextDefinition(1060799, "Purveyor of Darkness")),
|
||||
new RankDefinition(9, 950, 7, new TextDefinition(1060798, "Agent of Evil")),
|
||||
new RankDefinition(8, 900, 6, new TextDefinition(1060797, "Bringer of Sorrow")),
|
||||
new RankDefinition(7, 800, 6, new TextDefinition(1060797, "Bringer of Sorrow")),
|
||||
new RankDefinition(6, 700, 5, new TextDefinition(1060796, "Keeper of Lies")),
|
||||
new RankDefinition(5, 600, 5, new TextDefinition(1060796, "Keeper of Lies")),
|
||||
new RankDefinition(4, 500, 5, new TextDefinition(1060796, "Keeper of Lies")),
|
||||
new RankDefinition(3, 400, 4, new TextDefinition(1060795, "Servant")),
|
||||
new RankDefinition(2, 200, 4, new TextDefinition(1060795, "Servant")),
|
||||
new RankDefinition(1, 0, 4, new TextDefinition(1060795, "Servant"))
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new GuardDefinition(typeof(FactionHenchman), 0x1403, 5000, 1000, 10,
|
||||
new TextDefinition(1011526, "HENCHMAN"), new TextDefinition(1011510, "Hire Henchman")),
|
||||
new GuardDefinition(typeof(FactionMercenary), 0x0F62, 6000, 2000, 10,
|
||||
new TextDefinition(1011527, "MERCENARY"), new TextDefinition(1011511, "Hire Mercenary")),
|
||||
new GuardDefinition(typeof(FactionDeathKnight), 0x0F45, 7000, 3000, 10,
|
||||
new TextDefinition(1011512, "DEATH KNIGHT"), new TextDefinition(1011503, "Hire Death Knight")),
|
||||
new GuardDefinition(typeof(FactionNecromancer), 0x13F8, 8000, 4000, 10,
|
||||
new TextDefinition(1011513, "SHADOW MAGE"), new TextDefinition(1011504, "Hire Shadow Mage"))
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static Faction Instance{ get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class TrueBritannians : Faction
|
||||
{
|
||||
public TrueBritannians()
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
Definition =
|
||||
new FactionDefinition(
|
||||
2,
|
||||
1254, // dark purple
|
||||
2125, // gold
|
||||
2214, // join stone : gold
|
||||
2125, // broadcast : gold
|
||||
0x76, 0x3EB2, // war horse
|
||||
"True Britannians", "true", "TB",
|
||||
new TextDefinition(1011536, "LORD BRITISH"),
|
||||
new TextDefinition(1060771, "True Britannians faction"),
|
||||
new TextDefinition(1011423, "<center>TRUE BRITANNIANS</center>"),
|
||||
new TextDefinition(1011450,
|
||||
"True Britannians are loyal to the throne of Lord British. They refuse " +
|
||||
"to give up their homelands to the vile Minax, and detest the Shadowlords " +
|
||||
"for their evil ways. In addition, the Council of Mages threatens the " +
|
||||
"existence of their ruler, and as such they have armed themselves, and " +
|
||||
"prepare for war with all."),
|
||||
new TextDefinition(1011454, "This city is controlled by Lord British."),
|
||||
new TextDefinition(1042254, "This sigil has been corrupted by the True Britannians"),
|
||||
new TextDefinition(1041045, "The faction signup stone for the True Britannians"),
|
||||
new TextDefinition(1041383, "The Faction Stone of the True Britannians"),
|
||||
new TextDefinition(1011465, ": True Britannians"),
|
||||
new TextDefinition(1005181, "Followers of Lord British will now be ignored."),
|
||||
new TextDefinition(1005182, "Followers of Lord British will now be warned of their impending doom."),
|
||||
new TextDefinition(1005183, "Followers of Lord British will now be attacked on sight."),
|
||||
new StrongholdDefinition(
|
||||
new[]
|
||||
{
|
||||
new Rectangle2D(1292, 1556, 25, 25),
|
||||
new Rectangle2D(1292, 1676, 120, 25),
|
||||
new Rectangle2D(1388, 1556, 25, 25),
|
||||
new Rectangle2D(1317, 1563, 71, 18),
|
||||
new Rectangle2D(1300, 1581, 105, 95),
|
||||
new Rectangle2D(1405, 1612, 12, 21),
|
||||
new Rectangle2D(1405, 1633, 11, 5)
|
||||
},
|
||||
new Point3D(1419, 1622, 20),
|
||||
new Point3D(1330, 1621, 50),
|
||||
new[]
|
||||
{
|
||||
new Point3D(1328, 1627, 50),
|
||||
new Point3D(1328, 1621, 50),
|
||||
new Point3D(1334, 1627, 50),
|
||||
new Point3D(1334, 1621, 50),
|
||||
new Point3D(1340, 1627, 50),
|
||||
new Point3D(1340, 1621, 50),
|
||||
new Point3D(1345, 1621, 50),
|
||||
new Point3D(1345, 1627, 50)
|
||||
}),
|
||||
new[]
|
||||
{
|
||||
new RankDefinition(10, 991, 8, new TextDefinition(1060794, "Knight of the Codex")),
|
||||
new RankDefinition(9, 950, 7, new TextDefinition(1060793, "Knight of Virtue")),
|
||||
new RankDefinition(8, 900, 6, new TextDefinition(1060792, "Crusader")),
|
||||
new RankDefinition(7, 800, 6, new TextDefinition(1060792, "Crusader")),
|
||||
new RankDefinition(6, 700, 5, new TextDefinition(1060791, "Sentinel")),
|
||||
new RankDefinition(5, 600, 5, new TextDefinition(1060791, "Sentinel")),
|
||||
new RankDefinition(4, 500, 5, new TextDefinition(1060791, "Sentinel")),
|
||||
new RankDefinition(3, 400, 4, new TextDefinition(1060790, "Defender")),
|
||||
new RankDefinition(2, 200, 4, new TextDefinition(1060790, "Defender")),
|
||||
new RankDefinition(1, 0, 4, new TextDefinition(1060790, "Defender"))
|
||||
},
|
||||
new[]
|
||||
{
|
||||
new GuardDefinition(typeof(FactionHenchman), 0x1403, 5000, 1000, 10,
|
||||
new TextDefinition(1011526, "HENCHMAN"), new TextDefinition(1011510, "Hire Henchman")),
|
||||
new GuardDefinition(typeof(FactionMercenary), 0x0F62, 6000, 2000, 10,
|
||||
new TextDefinition(1011527, "MERCENARY"), new TextDefinition(1011511, "Hire Mercenary")),
|
||||
new GuardDefinition(typeof(FactionKnight), 0x0F4D, 7000, 3000, 10,
|
||||
new TextDefinition(1011528, "KNIGHT"), new TextDefinition(1011497, "Hire Knight")),
|
||||
new GuardDefinition(typeof(FactionPaladin), 0x143F, 8000, 4000, 10,
|
||||
new TextDefinition(1011529, "PALADIN"), new TextDefinition(1011498, "Hire Paladin"))
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static Faction Instance{ get; private set; }
|
||||
}
|
||||
}
|
||||
24
Projects/Scripts/Engines/Factions/Instances/Towns/Britain.cs
Normal file
24
Projects/Scripts/Engines/Factions/Instances/Towns/Britain.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class Britain : Town
|
||||
{
|
||||
public Britain()
|
||||
{
|
||||
Definition =
|
||||
new TownDefinition(
|
||||
0,
|
||||
0x1869,
|
||||
"Britain",
|
||||
"Britain",
|
||||
new TextDefinition(1011433, "BRITAIN"),
|
||||
new TextDefinition(1011561, "TOWN STONE FOR BRITAIN"),
|
||||
new TextDefinition(1041034, "The Faction Sigil Monolith of Britain"),
|
||||
new TextDefinition(1041404, "The Faction Town Sigil Monolith of Britain"),
|
||||
new TextDefinition(1041413, "Faction Town Stone of Britain"),
|
||||
new TextDefinition(1041395, "Faction Town Sigil of Britain"),
|
||||
new TextDefinition(1041386, "Corrupted Faction Town Sigil of Britain"),
|
||||
new Point3D(1592, 1680, 10),
|
||||
new Point3D(1588, 1676, 10));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class Magincia : Town
|
||||
{
|
||||
public Magincia()
|
||||
{
|
||||
Definition =
|
||||
new TownDefinition(
|
||||
7,
|
||||
0x1870,
|
||||
"Magincia",
|
||||
"Magincia",
|
||||
new TextDefinition(1011440, "MAGINCIA"),
|
||||
new TextDefinition(1011568, "TOWN STONE FOR MAGINCIA"),
|
||||
new TextDefinition(1041041, "The Faction Sigil Monolith of Magincia"),
|
||||
new TextDefinition(1041411, "The Faction Town Sigil Monolith of Magincia"),
|
||||
new TextDefinition(1041420, "Faction Town Stone of Magincia"),
|
||||
new TextDefinition(1041402, "Faction Town Sigil of Magincia"),
|
||||
new TextDefinition(1041393, "Corrupted Faction Town Sigil of Magincia"),
|
||||
new Point3D(3714, 2235, 20),
|
||||
new Point3D(3712, 2230, 20));
|
||||
}
|
||||
}
|
||||
}
|
||||
24
Projects/Scripts/Engines/Factions/Instances/Towns/Minoc.cs
Normal file
24
Projects/Scripts/Engines/Factions/Instances/Towns/Minoc.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class Minoc : Town
|
||||
{
|
||||
public Minoc()
|
||||
{
|
||||
Definition =
|
||||
new TownDefinition(
|
||||
2,
|
||||
0x186B,
|
||||
"Minoc",
|
||||
"Minoc",
|
||||
new TextDefinition(1011437, "MINOC"),
|
||||
new TextDefinition(1011564, "TOWN STONE FOR MINOC"),
|
||||
new TextDefinition(1041036, "The Faction Sigil Monolith of Minoc"),
|
||||
new TextDefinition(1041406, "The Faction Town Sigil Monolith Minoc"),
|
||||
new TextDefinition(1041415, "Faction Town Stone of Minoc"),
|
||||
new TextDefinition(1041397, "Faction Town Sigil of Minoc"),
|
||||
new TextDefinition(1041388, "Corrupted Faction Town Sigil of Minoc"),
|
||||
new Point3D(2471, 439, 15),
|
||||
new Point3D(2469, 445, 15));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class Moonglow : Town
|
||||
{
|
||||
public Moonglow()
|
||||
{
|
||||
Definition =
|
||||
new TownDefinition(
|
||||
3,
|
||||
0x186C,
|
||||
"Moonglow",
|
||||
"Moonglow",
|
||||
new TextDefinition(1011435, "MOONGLOW"),
|
||||
new TextDefinition(1011563, "TOWN STONE FOR MOONGLOW"),
|
||||
new TextDefinition(1041037, "The Faction Sigil Monolith of Moonglow"),
|
||||
new TextDefinition(1041407, "The Faction Town Sigil Monolith of Moonglow"),
|
||||
new TextDefinition(1041416, "Faction Town Stone of Moonglow"),
|
||||
new TextDefinition(1041398, "Faction Town Sigil of Moonglow"),
|
||||
new TextDefinition(1041389, "Corrupted Faction Town Sigil of Moonglow"),
|
||||
new Point3D(4436, 1083, 0),
|
||||
new Point3D(4432, 1086, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class SkaraBrae : Town
|
||||
{
|
||||
public SkaraBrae()
|
||||
{
|
||||
Definition =
|
||||
new TownDefinition(
|
||||
6,
|
||||
0x186F,
|
||||
"Skara Brae",
|
||||
"Skara Brae",
|
||||
new TextDefinition(1011439, "SKARA BRAE"),
|
||||
new TextDefinition(1011567, "TOWN STONE FOR SKARA BRAE"),
|
||||
new TextDefinition(1041040, "The Faction Sigil Monolith of Skara Brae"),
|
||||
new TextDefinition(1041410, "The Faction Town Sigil Monolith of Skara Brae"),
|
||||
new TextDefinition(1041419, "Faction Town Stone of Skara Brae"),
|
||||
new TextDefinition(1041401, "Faction Town Sigil of Skara Brae"),
|
||||
new TextDefinition(1041392, "Corrupted Faction Town Sigil of Skara Brae"),
|
||||
new Point3D(576, 2200, 0),
|
||||
new Point3D(572, 2196, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
24
Projects/Scripts/Engines/Factions/Instances/Towns/Trinsic.cs
Normal file
24
Projects/Scripts/Engines/Factions/Instances/Towns/Trinsic.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class Trinsic : Town
|
||||
{
|
||||
public Trinsic()
|
||||
{
|
||||
Definition =
|
||||
new TownDefinition(
|
||||
1,
|
||||
0x186A,
|
||||
"Trinsic",
|
||||
"Trinsic",
|
||||
new TextDefinition(1011434, "TRINSIC"),
|
||||
new TextDefinition(1011562, "TOWN STONE FOR TRINSIC"),
|
||||
new TextDefinition(1041035, "The Faction Sigil Monolith of Trinsic"),
|
||||
new TextDefinition(1041405, "The Faction Town Sigil Monolith of Trinsic"),
|
||||
new TextDefinition(1041414, "Faction Town Stone of Trinsic"),
|
||||
new TextDefinition(1041396, "Faction Town Sigil of Trinsic"),
|
||||
new TextDefinition(1041387, "Corrupted Faction Town Sigil of Trinsic"),
|
||||
new Point3D(1914, 2717, 20),
|
||||
new Point3D(1909, 2720, 20));
|
||||
}
|
||||
}
|
||||
}
|
||||
24
Projects/Scripts/Engines/Factions/Instances/Towns/Vesper.cs
Normal file
24
Projects/Scripts/Engines/Factions/Instances/Towns/Vesper.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class Vesper : Town
|
||||
{
|
||||
public Vesper()
|
||||
{
|
||||
Definition =
|
||||
new TownDefinition(
|
||||
5,
|
||||
0x186E,
|
||||
"Vesper",
|
||||
"Vesper",
|
||||
new TextDefinition(1016413, "VESPER"),
|
||||
new TextDefinition(1011566, "TOWN STONE FOR VESPER"),
|
||||
new TextDefinition(1041039, "The Faction Sigil Monolith of Vesper"),
|
||||
new TextDefinition(1041409, "The Faction Town Sigil Monolith of Vesper"),
|
||||
new TextDefinition(1041418, "Faction Town Stone of Vesper"),
|
||||
new TextDefinition(1041400, "Faction Town Sigil of Vesper"),
|
||||
new TextDefinition(1041391, "Corrupted Faction Town Sigil of Vesper"),
|
||||
new Point3D(2982, 818, 0),
|
||||
new Point3D(2985, 821, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
24
Projects/Scripts/Engines/Factions/Instances/Towns/Yew.cs
Normal file
24
Projects/Scripts/Engines/Factions/Instances/Towns/Yew.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class Yew : Town
|
||||
{
|
||||
public Yew()
|
||||
{
|
||||
Definition =
|
||||
new TownDefinition(
|
||||
4,
|
||||
0x186D,
|
||||
"Yew",
|
||||
"Yew",
|
||||
new TextDefinition(1011438, "YEW"),
|
||||
new TextDefinition(1011565, "TOWN STONE FOR YEW"),
|
||||
new TextDefinition(1041038, "The Faction Sigil Monolith of Yew"),
|
||||
new TextDefinition(1041408, "The Faction Town Sigil Monolith of Yew"),
|
||||
new TextDefinition(1041417, "Faction Town Stone of Yew"),
|
||||
new TextDefinition(1041399, "Faction Town Sigil of Yew"),
|
||||
new TextDefinition(1041390, "Corrupted Faction Town Sigil of Yew"),
|
||||
new Point3D(548, 979, 0),
|
||||
new Point3D(542, 980, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
129
Projects/Scripts/Engines/Factions/Items/BaseMonolith.cs
Normal file
129
Projects/Scripts/Engines/Factions/Items/BaseMonolith.cs
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public abstract class BaseMonolith : BaseSystemController
|
||||
{
|
||||
private Faction m_Faction;
|
||||
private Sigil m_Sigil;
|
||||
private Town m_Town;
|
||||
|
||||
public BaseMonolith(Town town = null, Faction faction = null) : base(0x1183)
|
||||
{
|
||||
Movable = false;
|
||||
Town = town;
|
||||
Faction = faction;
|
||||
Monoliths.Add(this);
|
||||
}
|
||||
|
||||
public BaseMonolith(Serial serial) : base(serial)
|
||||
{
|
||||
Monoliths.Add(this);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public Sigil Sigil
|
||||
{
|
||||
get => m_Sigil;
|
||||
set
|
||||
{
|
||||
if (m_Sigil == value)
|
||||
return;
|
||||
|
||||
m_Sigil = value;
|
||||
|
||||
if (m_Sigil?.LastMonolith != null && m_Sigil.LastMonolith != this && m_Sigil.LastMonolith.Sigil == m_Sigil)
|
||||
m_Sigil.LastMonolith.Sigil = null;
|
||||
|
||||
if (m_Sigil != null)
|
||||
m_Sigil.LastMonolith = this;
|
||||
|
||||
UpdateSigil();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public Town Town
|
||||
{
|
||||
get => m_Town;
|
||||
set
|
||||
{
|
||||
m_Town = value;
|
||||
OnTownChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public Faction Faction
|
||||
{
|
||||
get => m_Faction;
|
||||
set
|
||||
{
|
||||
m_Faction = value;
|
||||
Hue = m_Faction?.Definition.HuePrimary ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<BaseMonolith> Monoliths{ get; set; } = new List<BaseMonolith>();
|
||||
|
||||
public override void OnLocationChange(Point3D oldLocation)
|
||||
{
|
||||
base.OnLocationChange(oldLocation);
|
||||
UpdateSigil();
|
||||
}
|
||||
|
||||
public override void OnMapChange()
|
||||
{
|
||||
base.OnMapChange();
|
||||
UpdateSigil();
|
||||
}
|
||||
|
||||
public virtual void UpdateSigil()
|
||||
{
|
||||
if (m_Sigil?.Deleted != false)
|
||||
return;
|
||||
|
||||
m_Sigil.MoveToWorld(new Point3D(X, Y, Z + 18), Map);
|
||||
}
|
||||
|
||||
public virtual void OnTownChanged()
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
Monoliths.Remove(this);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
Town.WriteReference(writer, m_Town);
|
||||
Faction.WriteReference(writer, m_Faction);
|
||||
|
||||
writer.Write(m_Sigil);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Town = Town.ReadReference(reader);
|
||||
Faction = Faction.ReadReference(reader);
|
||||
m_Sigil = reader.ReadItem() as Sigil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public abstract class BaseSystemController : Item
|
||||
{
|
||||
private int m_LabelNumber;
|
||||
|
||||
public BaseSystemController(int itemID) : base(itemID)
|
||||
{
|
||||
}
|
||||
|
||||
public BaseSystemController(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual int DefaultLabelNumber => base.LabelNumber;
|
||||
public new virtual string DefaultName => null;
|
||||
|
||||
public override int LabelNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_LabelNumber > 0)
|
||||
return m_LabelNumber;
|
||||
|
||||
return DefaultLabelNumber;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void AssignName(TextDefinition name)
|
||||
{
|
||||
if (name != null && name.Number > 0)
|
||||
{
|
||||
m_LabelNumber = name.Number;
|
||||
Name = null;
|
||||
}
|
||||
else if (name?.String != null)
|
||||
{
|
||||
m_LabelNumber = 0;
|
||||
Name = name.String;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_LabelNumber = 0;
|
||||
Name = DefaultName;
|
||||
}
|
||||
|
||||
InvalidateProperties();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
99
Projects/Scripts/Engines/Factions/Items/FactionStone.cs
Normal file
99
Projects/Scripts/Engines/Factions/Items/FactionStone.cs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionStone : BaseSystemController
|
||||
{
|
||||
private Faction m_Faction;
|
||||
|
||||
[Constructible]
|
||||
public FactionStone(Faction faction = null) : base(0xEDC)
|
||||
{
|
||||
Movable = false;
|
||||
Faction = faction;
|
||||
}
|
||||
|
||||
public FactionStone(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public Faction Faction
|
||||
{
|
||||
get => m_Faction;
|
||||
set
|
||||
{
|
||||
m_Faction = value;
|
||||
|
||||
AssignName(m_Faction?.Definition.FactionStoneName);
|
||||
}
|
||||
}
|
||||
|
||||
public override string DefaultName => "faction stone";
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (m_Faction == null)
|
||||
return;
|
||||
|
||||
if (!from.InRange(GetWorldLocation(), 2))
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
|
||||
}
|
||||
else if (FactionGump.Exists(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1042160); // You already have a faction menu open.
|
||||
}
|
||||
else if (from is PlayerMobile mobile)
|
||||
{
|
||||
Faction existingFaction = Faction.Find(mobile);
|
||||
|
||||
if (existingFaction == m_Faction || mobile.AccessLevel >= AccessLevel.GameMaster)
|
||||
{
|
||||
PlayerState pl = PlayerState.Find(mobile);
|
||||
|
||||
if (pl != null && pl.IsLeaving)
|
||||
mobile.SendLocalizedMessage(
|
||||
1005051); // You cannot use the faction stone until you have finished quitting your current faction
|
||||
else
|
||||
mobile.SendGump(new FactionStoneGump(mobile, m_Faction));
|
||||
}
|
||||
else if (existingFaction != null)
|
||||
{
|
||||
// TODO: Validate
|
||||
mobile.SendLocalizedMessage(1005053); // This is not your faction stone!
|
||||
}
|
||||
else
|
||||
{
|
||||
mobile.SendGump(new JoinStoneGump(mobile, m_Faction));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
Faction.WriteReference(writer, m_Faction);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Faction = Faction.ReadReference(reader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
74
Projects/Scripts/Engines/Factions/Items/JoinStone.cs
Normal file
74
Projects/Scripts/Engines/Factions/Items/JoinStone.cs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class JoinStone : BaseSystemController
|
||||
{
|
||||
private Faction m_Faction;
|
||||
|
||||
[Constructible]
|
||||
public JoinStone(Faction faction = null) : base(0xEDC)
|
||||
{
|
||||
Movable = false;
|
||||
Faction = faction;
|
||||
}
|
||||
|
||||
public JoinStone(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public Faction Faction
|
||||
{
|
||||
get => m_Faction;
|
||||
set
|
||||
{
|
||||
m_Faction = value;
|
||||
|
||||
Hue = m_Faction?.Definition.HueJoin ?? 0;
|
||||
AssignName(m_Faction?.Definition.SignupName);
|
||||
}
|
||||
}
|
||||
|
||||
public override string DefaultName => "faction signup stone";
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (m_Faction == null)
|
||||
return;
|
||||
|
||||
if (!from.InRange(GetWorldLocation(), 2))
|
||||
from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that.
|
||||
else if (FactionGump.Exists(from))
|
||||
from.SendLocalizedMessage(1042160); // You already have a faction menu open.
|
||||
else if (Faction.Find(from) == null && from is PlayerMobile mobile)
|
||||
mobile.SendGump(new JoinStoneGump(mobile, m_Faction));
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
Faction.WriteReference(writer, m_Faction);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Faction = Faction.ReadReference(reader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class BloodRose : PowerFactionItem
|
||||
{
|
||||
public BloodRose()
|
||||
: base(Utility.RandomList(6378, 9035))
|
||||
{
|
||||
Hue = 2118;
|
||||
}
|
||||
|
||||
public BloodRose(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override string DefaultName => "blood rose";
|
||||
|
||||
public override bool Use(Mobile from)
|
||||
{
|
||||
if (from.GetStatMod("blood-rose") == null)
|
||||
{
|
||||
from.PlaySound(Utility.Random(0x3A, 3));
|
||||
|
||||
if (from.Body.IsHuman && !from.Mounted) from.Animate(34, 5, 1, true, false, 0);
|
||||
|
||||
int amount = Utility.Dice(3, 3, 3);
|
||||
int time = Utility.RandomMinMax(5, 30);
|
||||
|
||||
from.FixedParticles(0x373A, 10, 15, 5018, EffectLayer.Waist);
|
||||
|
||||
from.PlaySound(0x1EE);
|
||||
from.AddStatMod(new StatMod(StatType.All, "blood-rose", amount, TimeSpan.FromMinutes(time)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
from.SendLocalizedMessage(
|
||||
1062927); // You have eaten one of these recently and eating another would provide no benefit.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class ClarityPotion : PowerFactionItem
|
||||
{
|
||||
public ClarityPotion()
|
||||
: base(3628)
|
||||
{
|
||||
Hue = 1154;
|
||||
}
|
||||
|
||||
public ClarityPotion(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override string DefaultName => "clarity potion";
|
||||
|
||||
public override bool Use(Mobile from)
|
||||
{
|
||||
if (from.BeginAction<ClarityPotion>())
|
||||
{
|
||||
int amount = Utility.Dice(3, 3, 3);
|
||||
int time = Utility.RandomMinMax(5, 30);
|
||||
|
||||
from.PlaySound(0x2D6);
|
||||
|
||||
if (from.Body.IsHuman) from.Animate(34, 5, 1, true, false, 0);
|
||||
|
||||
from.FixedParticles(0x375A, 10, 15, 5011, EffectLayer.Head);
|
||||
from.PlaySound(0x1EB);
|
||||
|
||||
StatMod mod = from.GetStatMod("Concussion");
|
||||
|
||||
if (mod != null)
|
||||
{
|
||||
from.RemoveStatMod("Concussion");
|
||||
from.Mana -= mod.Offset;
|
||||
}
|
||||
|
||||
from.PlaySound(0x1EE);
|
||||
from.AddStatMod(new StatMod(StatType.Int, "clarity-potion", amount, TimeSpan.FromMinutes(time)));
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromMinutes(time), delegate { from.EndAction<ClarityPotion>(); });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
using Server.Factions;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class GemOfEmpowerment : PowerFactionItem
|
||||
{
|
||||
public GemOfEmpowerment()
|
||||
: base(7955)
|
||||
{
|
||||
Hue = 1154;
|
||||
}
|
||||
|
||||
public GemOfEmpowerment(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override string DefaultName => "gem of empowerment";
|
||||
|
||||
public override bool Use(Mobile from)
|
||||
{
|
||||
if (Faction.ClearSkillLoss(from))
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 2219, false, "The gem shatters as you invoke its power.");
|
||||
from.PlaySound(909);
|
||||
|
||||
from.FixedEffect(0x373A, 10, 30);
|
||||
from.PlaySound(0x209);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Server.Factions;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public abstract class PowerFactionItem : Item
|
||||
{
|
||||
private static WeightedItem[] _items =
|
||||
{
|
||||
new WeightedItem(30, typeof(GemOfEmpowerment)),
|
||||
new WeightedItem(25, typeof(BloodRose)),
|
||||
new WeightedItem(20, typeof(ClarityPotion)),
|
||||
new WeightedItem(15, typeof(UrnOfAscension)),
|
||||
new WeightedItem(10, typeof(StormsEye))
|
||||
};
|
||||
|
||||
public PowerFactionItem(int itemId)
|
||||
: base(itemId)
|
||||
{
|
||||
}
|
||||
|
||||
public PowerFactionItem(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract bool Use(Mobile mob);
|
||||
|
||||
public static void CheckSpawn(Mobile killer, Mobile victim)
|
||||
{
|
||||
if (killer != null && victim != null)
|
||||
{
|
||||
PlayerState ps = PlayerState.Find(victim);
|
||||
|
||||
if (ps != null)
|
||||
{
|
||||
int chance = ps.Rank.Rank;
|
||||
|
||||
if (chance > Utility.Random(100))
|
||||
{
|
||||
int weight = 0;
|
||||
|
||||
foreach (WeightedItem item in _items) weight += item.Weight;
|
||||
|
||||
weight = Utility.Random(weight);
|
||||
|
||||
foreach (WeightedItem item in _items)
|
||||
{
|
||||
if (weight < item.Weight)
|
||||
{
|
||||
Item obj = item.Construct();
|
||||
|
||||
if (obj != null)
|
||||
{
|
||||
killer.AddToBackpack(obj);
|
||||
|
||||
killer.SendSound(1470);
|
||||
killer.LocalOverheadMessage(
|
||||
MessageType.Regular, 2119, false,
|
||||
"You notice a strange item on the corpse, and decide to pick it up."
|
||||
);
|
||||
|
||||
try
|
||||
{
|
||||
using (StreamWriter op = new StreamWriter("faction-power-items.log", true))
|
||||
{
|
||||
op.WriteLine("{0}\t{1}\t{2}\t{3}", DateTime.UtcNow, killer, victim, obj);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
weight -= item.Weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (!IsChildOf(from.Backpack))
|
||||
{
|
||||
from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it.
|
||||
}
|
||||
else if (from is PlayerMobile mobile && mobile.DuelContext != null)
|
||||
{
|
||||
mobile.SendMessage("You can't use that.");
|
||||
}
|
||||
else if (Faction.Find(from) == null)
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 2119, false,
|
||||
"The object vanishes from your hands as you touch it.");
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(1.0),
|
||||
delegate
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 2118, false,
|
||||
"You feel a strange tingling sensation throughout your body.");
|
||||
});
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(4.0),
|
||||
delegate { from.LocalOverheadMessage(MessageType.Regular, 2118, false, "Your skin begins to burn."); });
|
||||
|
||||
new DestructionTimer(from).Start();
|
||||
Delete();
|
||||
|
||||
//from.SendMessage( "You must be in a faction to use this item." );
|
||||
}
|
||||
else if (Use(from))
|
||||
{
|
||||
from.RevealingAction();
|
||||
Consume();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
|
||||
private sealed class DestructionTimer : Timer
|
||||
{
|
||||
private Mobile _mobile;
|
||||
|
||||
private bool _screamed;
|
||||
|
||||
public DestructionTimer(Mobile mob)
|
||||
: base(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(0.1), 10)
|
||||
{
|
||||
_mobile = mob;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (_mobile.Alive)
|
||||
{
|
||||
if (!_screamed)
|
||||
{
|
||||
_screamed = true;
|
||||
|
||||
_mobile.PlaySound(_mobile.Female ? 814 : 1088);
|
||||
_mobile.PublicOverheadMessage(MessageType.Regular, 2118, false, "Aaaaah!");
|
||||
}
|
||||
|
||||
_mobile.Damage(Utility.Dice(2, 6, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class WeightedItem
|
||||
{
|
||||
public WeightedItem(int weight, Type type)
|
||||
{
|
||||
Weight = weight;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public int Weight{ get; }
|
||||
|
||||
public Type Type{ get; }
|
||||
|
||||
public Item Construct()
|
||||
{
|
||||
return Activator.CreateInstance(Type) as Item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Server.Factions;
|
||||
using Server.Spells;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class StormsEye : PowerFactionItem
|
||||
{
|
||||
public StormsEye()
|
||||
: base(3967)
|
||||
{
|
||||
Hue = 1165;
|
||||
}
|
||||
|
||||
public StormsEye(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override string DefaultName => "storms eye";
|
||||
|
||||
public override bool Use(Mobile user)
|
||||
{
|
||||
if (Movable)
|
||||
user.BeginTarget(12, true, TargetFlags.None, delegate(Mobile from, object obj)
|
||||
{
|
||||
if (Movable && !Deleted)
|
||||
if (obj is IPoint3D pt)
|
||||
{
|
||||
SpellHelper.GetSurfaceTop(ref pt);
|
||||
|
||||
Point3D origin = new Point3D(pt);
|
||||
Map facet = from.Map;
|
||||
|
||||
if (facet?.CanFit(pt.X, pt.Y, pt.Z, 16, false, false) != true)
|
||||
return;
|
||||
|
||||
Movable = false;
|
||||
|
||||
Effects.SendMovingEffect(
|
||||
from, new Entity(Serial.Zero, origin, facet),
|
||||
ItemID & 0x3FFF, 7, 0, false, false, Hue - 1
|
||||
);
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(0.5), delegate
|
||||
{
|
||||
Delete();
|
||||
|
||||
Effects.PlaySound(origin, facet, 530);
|
||||
Effects.PlaySound(origin, facet, 263);
|
||||
|
||||
Effects.SendLocationEffect(
|
||||
origin, facet,
|
||||
14284, 96, 1, 0, 2
|
||||
);
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(1.0), delegate
|
||||
{
|
||||
List<Mobile> targets = facet.GetMobilesInRange(origin, 12).Where(mob =>
|
||||
from.CanBeHarmful(mob, false) && mob.InLOS(new Point3D(origin, origin.Z + 1)) &&
|
||||
Faction.Find(mob) != null).ToList();
|
||||
|
||||
foreach (Mobile mob in targets)
|
||||
{
|
||||
int damage = mob.Hits * 6 / 10;
|
||||
|
||||
if (!mob.Player && damage < 10)
|
||||
damage = 10;
|
||||
else if (damage > 75)
|
||||
damage = 75;
|
||||
|
||||
Effects.SendMovingEffect(
|
||||
new Entity(Serial.Zero, new Point3D(origin, origin.Z + 4), facet), mob,
|
||||
14068, 1, 32, false, false, 1111, 2
|
||||
);
|
||||
|
||||
from.DoHarmful(mob);
|
||||
|
||||
SpellHelper.Damage(TimeSpan.FromSeconds(0.50), mob, from, damage / 3.0, 0, 0, 0, 0,
|
||||
100);
|
||||
SpellHelper.Damage(TimeSpan.FromSeconds(0.70), mob, from, damage / 3.0, 0, 0, 0, 0,
|
||||
100);
|
||||
SpellHelper.Damage(TimeSpan.FromSeconds(1.00), mob, from, damage / 3.0, 0, 0, 0, 0,
|
||||
100);
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(0.50), delegate { mob.PlaySound(0x1FB); });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
using Server.Factions;
|
||||
using Server.Gumps;
|
||||
using Server.Multis;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class UrnOfAscension : PowerFactionItem
|
||||
{
|
||||
public UrnOfAscension()
|
||||
: base(9246)
|
||||
{
|
||||
}
|
||||
|
||||
public UrnOfAscension(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override string DefaultName => "urn of ascension";
|
||||
|
||||
public override bool Use(Mobile from)
|
||||
{
|
||||
Faction ourFaction = Faction.Find(from);
|
||||
|
||||
bool used = false;
|
||||
|
||||
foreach (Mobile mob in from.GetMobilesInRange(8))
|
||||
if (mob.Player && !mob.Alive && from.InLOS(mob))
|
||||
{
|
||||
if (Faction.Find(mob) != ourFaction) continue;
|
||||
|
||||
BaseHouse house = BaseHouse.FindHouseAt(mob);
|
||||
|
||||
if (house == null || house.IsFriend(from) || house.IsFriend(mob))
|
||||
{
|
||||
Faction.ClearSkillLoss(mob);
|
||||
|
||||
mob.SendGump(new ResurrectGump(mob, from));
|
||||
used = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (used)
|
||||
{
|
||||
from.LocalOverheadMessage(MessageType.Regular, 2219, false, "The urn shatters as you invoke its power.");
|
||||
from.PlaySound(64);
|
||||
|
||||
Effects.PlaySound(from.Location, from.Map, 1481);
|
||||
}
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
456
Projects/Scripts/Engines/Factions/Items/Sigil.cs
Normal file
456
Projects/Scripts/Engines/Factions/Items/Sigil.cs
Normal file
|
|
@ -0,0 +1,456 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class Sigil : BaseSystemController
|
||||
{
|
||||
public const int OwnershipHue = 0xB;
|
||||
|
||||
// ?? time corrupting faction has to return the sigil before corruption time resets ?
|
||||
public static readonly TimeSpan CorruptionGrace = TimeSpan.FromMinutes(Core.SE ? 30.0 : 15.0);
|
||||
|
||||
// Sigil must be held at a stronghold for this amount of time in order to become corrupted
|
||||
public static readonly TimeSpan CorruptionPeriod = Core.SE ? TimeSpan.FromHours(10.0) : TimeSpan.FromHours(24.0);
|
||||
|
||||
// After a sigil has been corrupted it must be returned to the town within this period of time
|
||||
public static readonly TimeSpan ReturnPeriod = TimeSpan.FromHours(1.0);
|
||||
|
||||
// Once it's been returned the corrupting faction owns the town for this period of time
|
||||
public static readonly TimeSpan PurificationPeriod = TimeSpan.FromDays(3.0);
|
||||
private Faction m_Corrupted;
|
||||
private Faction m_Corrupting;
|
||||
|
||||
private Town m_Town;
|
||||
|
||||
public Sigil(Town town) : base(0x1869)
|
||||
{
|
||||
Movable = false;
|
||||
Town = town;
|
||||
|
||||
Sigils.Add(this);
|
||||
}
|
||||
|
||||
public Sigil(Serial serial) : base(serial)
|
||||
{
|
||||
Sigils.Add(this);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public DateTime LastStolen{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public DateTime GraceStart{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public DateTime CorruptionStart{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public DateTime PurificationStart{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public Town Town
|
||||
{
|
||||
get => m_Town;
|
||||
set
|
||||
{
|
||||
m_Town = value;
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public Faction Corrupted
|
||||
{
|
||||
get => m_Corrupted;
|
||||
set
|
||||
{
|
||||
m_Corrupted = value;
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public Faction Corrupting
|
||||
{
|
||||
get => m_Corrupting;
|
||||
set
|
||||
{
|
||||
m_Corrupting = value;
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public BaseMonolith LastMonolith{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public bool IsBeingCorrupted => LastMonolith is StrongholdMonolith && LastMonolith.Faction == m_Corrupting &&
|
||||
m_Corrupting != null;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public bool IsCorrupted => m_Corrupted != null;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public bool IsPurifying => PurificationStart != DateTime.MinValue;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public bool IsCorrupting => m_Corrupting != null && m_Corrupting != m_Corrupted;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TimeSpan TimeUntilCorruption
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsBeingCorrupted)
|
||||
return TimeSpan.Zero;
|
||||
|
||||
TimeSpan ts = CorruptionStart + CorruptionPeriod - DateTime.UtcNow;
|
||||
|
||||
if (ts < TimeSpan.Zero)
|
||||
ts = TimeSpan.Zero;
|
||||
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Sigil> Sigils{ get; } = new List<Sigil>();
|
||||
|
||||
public void Update()
|
||||
{
|
||||
ItemID = m_Town?.Definition.SigilID ?? 0x1869;
|
||||
|
||||
if (m_Town == null)
|
||||
AssignName(null);
|
||||
else if (IsCorrupted || IsPurifying)
|
||||
AssignName(m_Town.Definition.CorruptedSigilName);
|
||||
else
|
||||
AssignName(m_Town.Definition.SigilName);
|
||||
|
||||
InvalidateProperties();
|
||||
}
|
||||
|
||||
public override void GetProperties(ObjectPropertyList list)
|
||||
{
|
||||
base.GetProperties(list);
|
||||
|
||||
if (IsCorrupted)
|
||||
TextDefinition.AddTo(list, m_Corrupted.Definition.SigilControl);
|
||||
else
|
||||
list.Add(1042256); // This sigil is not corrupted.
|
||||
|
||||
if (IsCorrupting)
|
||||
list.Add(1042257); // This sigil is in the process of being corrupted.
|
||||
else if (IsPurifying)
|
||||
list.Add(1042258); // This sigil has recently been corrupted, and is undergoing purification.
|
||||
else
|
||||
list.Add(1042259); // This sigil is not in the process of being corrupted.
|
||||
}
|
||||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
base.OnSingleClick(from);
|
||||
|
||||
if (IsCorrupted)
|
||||
{
|
||||
if (m_Corrupted.Definition.SigilControl.Number > 0)
|
||||
LabelTo(from, m_Corrupted.Definition.SigilControl.Number);
|
||||
else if (m_Corrupted.Definition.SigilControl.String != null)
|
||||
LabelTo(from, m_Corrupted.Definition.SigilControl.String);
|
||||
}
|
||||
else
|
||||
{
|
||||
LabelTo(from, 1042256); // This sigil is not corrupted.
|
||||
}
|
||||
|
||||
if (IsCorrupting)
|
||||
LabelTo(from, 1042257); // This sigil is in the process of being corrupted.
|
||||
else if (IsPurifying)
|
||||
LabelTo(from, 1042258); // This sigil has been recently corrupted, and is undergoing purification.
|
||||
else
|
||||
LabelTo(from, 1042259); // This sigil is not in the process of being corrupted.
|
||||
}
|
||||
|
||||
public override bool CheckLift(Mobile from, Item item, ref LRReason reject)
|
||||
{
|
||||
from.SendLocalizedMessage(1005225); // You must use the stealing skill to pick up the sigil
|
||||
return false;
|
||||
}
|
||||
|
||||
private Mobile FindOwner(IEntity parent)
|
||||
{
|
||||
if (parent is Item item)
|
||||
return item.RootParent as Mobile;
|
||||
|
||||
if (parent is Mobile mobile)
|
||||
return mobile;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void OnAdded(IEntity parent)
|
||||
{
|
||||
base.OnAdded(parent);
|
||||
|
||||
Mobile mob = FindOwner(parent);
|
||||
|
||||
if (mob != null)
|
||||
mob.SolidHueOverride = OwnershipHue;
|
||||
}
|
||||
|
||||
public override void OnRemoved(IEntity parent)
|
||||
{
|
||||
base.OnRemoved(parent);
|
||||
|
||||
Mobile mob = FindOwner(parent);
|
||||
|
||||
if (mob != null)
|
||||
mob.SolidHueOverride = -1;
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (IsChildOf(from.Backpack))
|
||||
{
|
||||
from.BeginTarget(1, false, TargetFlags.None, Sigil_OnTarget);
|
||||
from.SendLocalizedMessage(1042251); // Click on a sigil monolith or player
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ExistsOn(Mobile mob)
|
||||
{
|
||||
return mob.Backpack?.FindItemByType<Sigil>() != null;
|
||||
}
|
||||
|
||||
private void BeginCorrupting(Faction faction)
|
||||
{
|
||||
m_Corrupting = faction;
|
||||
CorruptionStart = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
private void ClearCorrupting()
|
||||
{
|
||||
m_Corrupting = null;
|
||||
CorruptionStart = DateTime.MinValue;
|
||||
}
|
||||
|
||||
private void Sigil_OnTarget(Mobile from, object obj)
|
||||
{
|
||||
if (Deleted || !IsChildOf(from.Backpack))
|
||||
return;
|
||||
|
||||
#region Give To Mobile
|
||||
|
||||
if (obj is Mobile)
|
||||
{
|
||||
if (obj is PlayerMobile targ)
|
||||
{
|
||||
Faction toFaction = Faction.Find(targ);
|
||||
Faction fromFaction = Faction.Find(from);
|
||||
|
||||
if (toFaction == null)
|
||||
{
|
||||
from.SendLocalizedMessage(1005223); // You cannot give the sigil to someone not in a faction
|
||||
}
|
||||
else if (fromFaction != toFaction)
|
||||
{
|
||||
from.SendLocalizedMessage(1005222); // You cannot give the sigil to someone not in your faction
|
||||
}
|
||||
else if (ExistsOn(targ))
|
||||
{
|
||||
from.SendLocalizedMessage(1005220); // You cannot give this sigil to someone who already has a sigil
|
||||
}
|
||||
else if (!targ.Alive)
|
||||
{
|
||||
from.SendLocalizedMessage(1042248); // You cannot give a sigil to a dead person.
|
||||
}
|
||||
else if (from.NetState != null && targ.NetState != null)
|
||||
{
|
||||
Container pack = targ.Backpack;
|
||||
|
||||
pack?.DropItem(this);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(1005221); //You cannot give the sigil to them
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
else if (obj is BaseMonolith)
|
||||
{
|
||||
#region Put in Stronghold
|
||||
|
||||
if (obj is StrongholdMonolith sm)
|
||||
{
|
||||
if (sm.Faction == null || sm.Faction != Faction.Find(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1042246); // You can't place that on an enemy monolith
|
||||
}
|
||||
else if (sm.Town == null || sm.Town != m_Town)
|
||||
{
|
||||
from.SendLocalizedMessage(1042247); // That is not the correct faction monolith
|
||||
}
|
||||
else
|
||||
{
|
||||
sm.Sigil = this;
|
||||
|
||||
Faction newController = sm.Faction;
|
||||
Faction oldController = m_Corrupting;
|
||||
|
||||
if (oldController == null)
|
||||
{
|
||||
if (m_Corrupted != newController)
|
||||
BeginCorrupting(newController);
|
||||
}
|
||||
else if (GraceStart > DateTime.MinValue && GraceStart + CorruptionGrace < DateTime.UtcNow)
|
||||
{
|
||||
if (m_Corrupted != newController)
|
||||
BeginCorrupting(newController); // grace time over, reset period
|
||||
else
|
||||
ClearCorrupting();
|
||||
|
||||
GraceStart = DateTime.MinValue;
|
||||
}
|
||||
else if (newController == oldController)
|
||||
{
|
||||
GraceStart = DateTime.MinValue; // returned within grace period
|
||||
}
|
||||
else if (GraceStart == DateTime.MinValue)
|
||||
{
|
||||
GraceStart = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
PurificationStart = DateTime.MinValue;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Put in Town
|
||||
|
||||
else if (obj is TownMonolith tm)
|
||||
{
|
||||
if (tm.Town == null || tm.Town != m_Town)
|
||||
{
|
||||
from.SendLocalizedMessage(1042245); // This is not the correct town sigil monolith
|
||||
}
|
||||
else if (m_Corrupted == null || m_Corrupted != Faction.Find(from))
|
||||
{
|
||||
from.SendLocalizedMessage(
|
||||
1042244); // Your faction did not corrupt this sigil. Take it to your stronghold.
|
||||
}
|
||||
else
|
||||
{
|
||||
tm.Sigil = this;
|
||||
|
||||
m_Corrupting = null;
|
||||
PurificationStart = DateTime.UtcNow;
|
||||
CorruptionStart = DateTime.MinValue;
|
||||
|
||||
m_Town.Capture(m_Corrupted);
|
||||
m_Corrupted = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(1005224); // You can't use the sigil on that
|
||||
}
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
Town.WriteReference(writer, m_Town);
|
||||
Faction.WriteReference(writer, m_Corrupted);
|
||||
Faction.WriteReference(writer, m_Corrupting);
|
||||
|
||||
writer.Write(LastMonolith);
|
||||
|
||||
writer.Write(LastStolen);
|
||||
writer.Write(GraceStart);
|
||||
writer.Write(CorruptionStart);
|
||||
writer.Write(PurificationStart);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Town = Town.ReadReference(reader);
|
||||
m_Corrupted = Faction.ReadReference(reader);
|
||||
m_Corrupting = Faction.ReadReference(reader);
|
||||
|
||||
LastMonolith = reader.ReadItem() as BaseMonolith;
|
||||
|
||||
LastStolen = reader.ReadDateTime();
|
||||
GraceStart = reader.ReadDateTime();
|
||||
CorruptionStart = reader.ReadDateTime();
|
||||
PurificationStart = reader.ReadDateTime();
|
||||
|
||||
Update();
|
||||
|
||||
if (RootParent is Mobile mob)
|
||||
mob.SolidHueOverride = OwnershipHue;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReturnHome()
|
||||
{
|
||||
BaseMonolith monolith = LastMonolith;
|
||||
|
||||
if (monolith == null && m_Town != null)
|
||||
monolith = m_Town.Monolith;
|
||||
|
||||
if (monolith?.Deleted == false)
|
||||
monolith.Sigil = this;
|
||||
|
||||
return monolith?.Deleted == false;
|
||||
}
|
||||
|
||||
public override void OnParentDeleted(IEntity parent)
|
||||
{
|
||||
base.OnParentDeleted(parent);
|
||||
|
||||
ReturnHome();
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
|
||||
Sigils.Remove(this);
|
||||
}
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
if (ReturnHome())
|
||||
return;
|
||||
|
||||
base.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
51
Projects/Scripts/Engines/Factions/Items/Silver.cs
Normal file
51
Projects/Scripts/Engines/Factions/Items/Silver.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class Silver : Item
|
||||
{
|
||||
[Constructible]
|
||||
public Silver() : this(1)
|
||||
{
|
||||
}
|
||||
|
||||
[Constructible]
|
||||
public Silver(int amountFrom, int amountTo) : this(Utility.RandomMinMax(amountFrom, amountTo))
|
||||
{
|
||||
}
|
||||
|
||||
[Constructible]
|
||||
public Silver(int amount) : base(0xEF0)
|
||||
{
|
||||
Stackable = true;
|
||||
Amount = amount;
|
||||
}
|
||||
|
||||
public Silver(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override double DefaultWeight => 0.02;
|
||||
|
||||
public override int GetDropSound()
|
||||
{
|
||||
if (Amount <= 1)
|
||||
return 0x2E4;
|
||||
if (Amount <= 5)
|
||||
return 0x2E5;
|
||||
return 0x2E6;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class StrongholdMonolith : BaseMonolith
|
||||
{
|
||||
public StrongholdMonolith(Town town = null, Faction faction = null) : base(town, faction)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public StrongholdMonolith(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int DefaultLabelNumber => 1041042; // A Faction Sigil Monolith
|
||||
|
||||
public override void OnTownChanged()
|
||||
{
|
||||
AssignName(Town?.Definition.StrongholdMonolithName);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Projects/Scripts/Engines/Factions/Items/TownMonolith.cs
Normal file
34
Projects/Scripts/Engines/Factions/Items/TownMonolith.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class TownMonolith : BaseMonolith
|
||||
{
|
||||
public TownMonolith(Town town = null) : base(town)
|
||||
{
|
||||
}
|
||||
|
||||
public TownMonolith(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int DefaultLabelNumber => 1041403; // A Faction Town Sigil Monolith
|
||||
|
||||
public override void OnTownChanged()
|
||||
{
|
||||
AssignName(Town?.Definition.TownMonolithName);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
79
Projects/Scripts/Engines/Factions/Items/TownStone.cs
Normal file
79
Projects/Scripts/Engines/Factions/Items/TownStone.cs
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class TownStone : BaseSystemController
|
||||
{
|
||||
private Town m_Town;
|
||||
|
||||
[Constructible]
|
||||
public TownStone(Town town = null) : base(0xEDE)
|
||||
{
|
||||
Movable = false;
|
||||
Town = town;
|
||||
}
|
||||
|
||||
public TownStone(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public Town Town
|
||||
{
|
||||
get => m_Town;
|
||||
set
|
||||
{
|
||||
m_Town = value;
|
||||
|
||||
AssignName(m_Town?.Definition.TownStoneName);
|
||||
}
|
||||
}
|
||||
|
||||
public override string DefaultName => "faction town stone";
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (m_Town == null)
|
||||
return;
|
||||
|
||||
Faction faction = Faction.Find(from);
|
||||
|
||||
if (faction == null && from.AccessLevel < AccessLevel.GameMaster)
|
||||
return; // TODO: Message?
|
||||
|
||||
if (m_Town.Owner == null || from.AccessLevel < AccessLevel.GameMaster && faction != m_Town.Owner)
|
||||
from.SendLocalizedMessage(1010332); // Your faction does not control this town
|
||||
else if (!m_Town.Owner.IsCommander(from))
|
||||
from.SendLocalizedMessage(1005242); // Only faction Leaders can use townstones
|
||||
else if (FactionGump.Exists(from))
|
||||
from.SendLocalizedMessage(1042160); // You already have a faction menu open.
|
||||
else if (from is PlayerMobile mobile)
|
||||
mobile.SendGump(new TownStoneGump(mobile, m_Town.Owner, m_Town));
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
Town.WriteReference(writer, m_Town);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Town = Town.ReadReference(reader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
264
Projects/Scripts/Engines/Factions/Items/Traps/BaseFactionTrap.cs
Normal file
264
Projects/Scripts/Engines/Factions/Items/Traps/BaseFactionTrap.cs
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
using System;
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public enum AllowedPlacing
|
||||
{
|
||||
Everywhere,
|
||||
|
||||
AnyFactionTown,
|
||||
ControlledFactionTown,
|
||||
FactionStronghold
|
||||
}
|
||||
|
||||
public abstract class BaseFactionTrap : BaseTrap
|
||||
{
|
||||
private Timer m_Concealing;
|
||||
|
||||
public BaseFactionTrap(Faction f, Mobile m, int itemID) : base(itemID)
|
||||
{
|
||||
Visible = false;
|
||||
|
||||
Faction = f;
|
||||
TimeOfPlacement = DateTime.UtcNow;
|
||||
Placer = m;
|
||||
}
|
||||
|
||||
public BaseFactionTrap(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Faction Faction{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Mobile Placer{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public DateTime TimeOfPlacement{ get; set; }
|
||||
|
||||
public virtual int EffectSound => 0;
|
||||
|
||||
public virtual int SilverFromDisarm => 100;
|
||||
|
||||
public virtual int MessageHue => 0;
|
||||
|
||||
public virtual int AttackMessage => 0;
|
||||
public virtual int DisarmMessage => 0;
|
||||
|
||||
public virtual AllowedPlacing AllowedPlacing => AllowedPlacing.Everywhere;
|
||||
|
||||
public virtual TimeSpan ConcealPeriod => TimeSpan.FromMinutes(1.0);
|
||||
|
||||
public virtual TimeSpan DecayPeriod
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Core.AOS)
|
||||
return TimeSpan.FromDays(1.0);
|
||||
|
||||
return TimeSpan.MaxValue; // no decay
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnTrigger(Mobile from)
|
||||
{
|
||||
if (!IsEnemy(from))
|
||||
return;
|
||||
|
||||
Conceal();
|
||||
|
||||
DoVisibleEffect();
|
||||
Effects.PlaySound(Location, Map, EffectSound);
|
||||
DoAttackEffect(from);
|
||||
|
||||
int silverToAward = from.Alive ? 20 : 40;
|
||||
|
||||
if (silverToAward > 0 && Placer != null && Faction != null)
|
||||
{
|
||||
PlayerState victimState = PlayerState.Find(from);
|
||||
|
||||
if (victimState?.CanGiveSilverTo(Placer) == true && victimState.KillPoints > 0)
|
||||
{
|
||||
int silverGiven = Faction.AwardSilver(Placer, silverToAward);
|
||||
|
||||
if (silverGiven > 0)
|
||||
{
|
||||
// TODO: Get real message
|
||||
if (from.Alive)
|
||||
Placer.SendMessage("You have earned {0} silver pieces because {1} fell for your trap.",
|
||||
silverGiven, from.Name);
|
||||
else
|
||||
Placer.SendLocalizedMessage(1042736,
|
||||
$"{silverGiven} silver\t{from.Name}"); // You have earned ~1_SILVER_AMOUNT~ pieces for vanquishing ~2_PLAYER_NAME~!
|
||||
}
|
||||
|
||||
victimState.OnGivenSilverTo(Placer);
|
||||
}
|
||||
}
|
||||
|
||||
from.LocalOverheadMessage(MessageType.Regular, MessageHue, AttackMessage);
|
||||
}
|
||||
|
||||
public abstract void DoVisibleEffect();
|
||||
public abstract void DoAttackEffect(Mobile m);
|
||||
|
||||
public virtual int IsValidLocation()
|
||||
{
|
||||
return IsValidLocation(GetWorldLocation(), Map);
|
||||
}
|
||||
|
||||
public virtual int IsValidLocation(Point3D p, Map m)
|
||||
{
|
||||
if (m == null)
|
||||
return 502956; // You cannot place a trap on that.
|
||||
|
||||
if (Core.ML)
|
||||
foreach (Item item in m.GetItemsInRange(p, 0))
|
||||
if (item is BaseFactionTrap trap && trap.Faction == Faction)
|
||||
return 1075263; // There is already a trap belonging to your faction at this location.;
|
||||
|
||||
switch (AllowedPlacing)
|
||||
{
|
||||
case AllowedPlacing.FactionStronghold:
|
||||
{
|
||||
StrongholdRegion region = Region.Find(p, m).GetRegion<StrongholdRegion>();
|
||||
|
||||
if (region != null && region.Faction == Faction)
|
||||
return 0;
|
||||
|
||||
return 1010355; // This trap can only be placed in your stronghold
|
||||
}
|
||||
case AllowedPlacing.AnyFactionTown:
|
||||
{
|
||||
Town town = Town.FromRegion(Region.Find(p, m));
|
||||
|
||||
if (town != null)
|
||||
return 0;
|
||||
|
||||
return 1010356; // This trap can only be placed in a faction town
|
||||
}
|
||||
case AllowedPlacing.ControlledFactionTown:
|
||||
{
|
||||
Town town = Town.FromRegion(Region.Find(p, m));
|
||||
|
||||
if (town != null && town.Owner == Faction)
|
||||
return 0;
|
||||
|
||||
return 1010357; // This trap can only be placed in a town your faction controls
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override void OnMovement(Mobile m, Point3D oldLocation)
|
||||
{
|
||||
base.OnMovement(m, oldLocation);
|
||||
|
||||
if (!CheckDecay() && CheckRange(m.Location, oldLocation, 6))
|
||||
if (Faction.Find(m) != null &&
|
||||
(m.Skills.DetectHidden.Value - 80.0) / 20.0 > Utility.RandomDouble())
|
||||
PrivateOverheadLocalizedMessage(m, 1010154, MessageHue, "", ""); // [Faction Trap]
|
||||
}
|
||||
|
||||
public void PrivateOverheadLocalizedMessage(Mobile to, int number, int hue, string name, string args)
|
||||
{
|
||||
NetState ns = to?.NetState;
|
||||
|
||||
ns?.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, hue, 3, number, name, args));
|
||||
}
|
||||
|
||||
public virtual bool CheckDecay()
|
||||
{
|
||||
TimeSpan decayPeriod = DecayPeriod;
|
||||
|
||||
if (decayPeriod == TimeSpan.MaxValue)
|
||||
return false;
|
||||
|
||||
if (TimeOfPlacement + decayPeriod < DateTime.UtcNow)
|
||||
{
|
||||
Timer.DelayCall(TimeSpan.Zero, Delete);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual void BeginConceal()
|
||||
{
|
||||
m_Concealing?.Stop();
|
||||
|
||||
m_Concealing = Timer.DelayCall(ConcealPeriod, Conceal);
|
||||
}
|
||||
|
||||
public virtual void Conceal()
|
||||
{
|
||||
m_Concealing?.Stop();
|
||||
|
||||
m_Concealing = null;
|
||||
|
||||
if (!Deleted)
|
||||
Visible = false;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
Faction.WriteReference(writer, Faction);
|
||||
writer.Write(Placer);
|
||||
writer.Write(TimeOfPlacement);
|
||||
|
||||
if (Visible)
|
||||
BeginConceal();
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
Faction = Faction.ReadReference(reader);
|
||||
Placer = reader.ReadMobile();
|
||||
TimeOfPlacement = reader.ReadDateTime();
|
||||
|
||||
if (Visible)
|
||||
BeginConceal();
|
||||
|
||||
CheckDecay();
|
||||
}
|
||||
|
||||
public override void OnDelete()
|
||||
{
|
||||
if (Faction?.Traps.Contains(this) == true)
|
||||
Faction.Traps.Remove(this);
|
||||
|
||||
base.OnDelete();
|
||||
}
|
||||
|
||||
public virtual bool IsEnemy(Mobile mob)
|
||||
{
|
||||
if (mob.Hidden && mob.AccessLevel > AccessLevel.Player)
|
||||
return false;
|
||||
|
||||
if (!mob.Alive || mob.IsDeadBondedPet)
|
||||
return false;
|
||||
|
||||
Faction faction = Faction.Find(mob, true);
|
||||
|
||||
if (faction == null && mob is BaseFactionGuard guard)
|
||||
faction = guard.Faction;
|
||||
|
||||
if (faction == null)
|
||||
return false;
|
||||
|
||||
return faction != Faction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
using System;
|
||||
using Server.Engines.Craft;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public abstract class BaseFactionTrapDeed : Item, ICraftable
|
||||
{
|
||||
private Faction m_Faction;
|
||||
|
||||
public BaseFactionTrapDeed(int itemID= 0x14F0) : base(itemID)
|
||||
{
|
||||
Weight = 1.0;
|
||||
LootType = LootType.Blessed;
|
||||
}
|
||||
|
||||
public BaseFactionTrapDeed(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract Type TrapType{ get; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Faction Faction
|
||||
{
|
||||
get => m_Faction;
|
||||
set
|
||||
{
|
||||
m_Faction = value;
|
||||
|
||||
if (m_Faction != null)
|
||||
Hue = m_Faction.Definition.HuePrimary;
|
||||
}
|
||||
}
|
||||
|
||||
#region ICraftable Members
|
||||
|
||||
public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool,
|
||||
CraftItem craftItem, int resHue)
|
||||
{
|
||||
ItemID = 0x14F0;
|
||||
Faction = Faction.Find(from);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public virtual BaseFactionTrap Construct(Mobile from)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Activator.CreateInstance(TrapType, m_Faction, from) as BaseFactionTrap;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
Faction faction = Faction.Find(from);
|
||||
|
||||
if (faction == null)
|
||||
{
|
||||
from.SendLocalizedMessage(1010353, "", 0x23); // Only faction members may place faction traps
|
||||
}
|
||||
else if (faction != m_Faction)
|
||||
{
|
||||
from.SendLocalizedMessage(1010354, "", 0x23); // You may only place faction traps created by your faction
|
||||
}
|
||||
else if (faction.Traps.Count >= faction.MaximumTraps)
|
||||
{
|
||||
from.SendLocalizedMessage(1010358, "", 0x23); // Your faction already has the maximum number of traps placed
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseFactionTrap trap = Construct(from);
|
||||
|
||||
if (trap == null)
|
||||
return;
|
||||
|
||||
int message = trap.IsValidLocation(from.Location, from.Map);
|
||||
|
||||
if (message > 0)
|
||||
{
|
||||
from.SendLocalizedMessage(message, "", 0x23);
|
||||
trap.Delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(1010360); // You arm the trap and carefully hide it from view
|
||||
trap.MoveToWorld(from.Location, from.Map);
|
||||
faction.Traps.Add(trap);
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
Faction.WriteReference(writer, m_Faction);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
m_Faction = Faction.ReadReference(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionExplosionTrap : BaseFactionTrap
|
||||
{
|
||||
public FactionExplosionTrap(Faction f = null, Mobile m = null) : base(f, m, 0x11C1)
|
||||
{
|
||||
}
|
||||
|
||||
public FactionExplosionTrap(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1044599; // faction explosion trap
|
||||
|
||||
public override int AttackMessage => 1010543; // You are enveloped in an explosion of fire!
|
||||
public override int DisarmMessage => 1010539; // You carefully remove the pressure trigger and disable the trap.
|
||||
public override int EffectSound => 0x307;
|
||||
public override int MessageHue => 0x78;
|
||||
|
||||
public override AllowedPlacing AllowedPlacing => AllowedPlacing.AnyFactionTown;
|
||||
|
||||
public override void DoVisibleEffect()
|
||||
{
|
||||
Effects.SendLocationEffect(GetWorldLocation(), Map, 0x36BD, 15, 10);
|
||||
}
|
||||
|
||||
public override void DoAttackEffect(Mobile m)
|
||||
{
|
||||
m.Damage(Utility.Dice(6, 10, 40), m);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class FactionExplosionTrapDeed : BaseFactionTrapDeed
|
||||
{
|
||||
public FactionExplosionTrapDeed() : base(0x36D2)
|
||||
{
|
||||
}
|
||||
|
||||
public FactionExplosionTrapDeed(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type TrapType => typeof(FactionExplosionTrap);
|
||||
public override int LabelNumber => 1044603; // faction explosion trap deed
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionGasTrap : BaseFactionTrap
|
||||
{
|
||||
public FactionGasTrap(Faction f = null, Mobile m = null) : base(f, m, 0x113C)
|
||||
{
|
||||
}
|
||||
|
||||
public FactionGasTrap(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1044598; // faction gas trap
|
||||
|
||||
public override int AttackMessage => 1010542; // A noxious green cloud of poison gas envelops you!
|
||||
public override int DisarmMessage => 502376; // The poison leaks harmlessly away due to your deft touch.
|
||||
public override int EffectSound => 0x230;
|
||||
public override int MessageHue => 0x44;
|
||||
|
||||
public override AllowedPlacing AllowedPlacing => AllowedPlacing.FactionStronghold;
|
||||
|
||||
public override void DoVisibleEffect()
|
||||
{
|
||||
Effects.SendLocationEffect(Location, Map, 0x3709, 28, 10, 0x1D3, 5);
|
||||
}
|
||||
|
||||
public override void DoAttackEffect(Mobile m)
|
||||
{
|
||||
m.ApplyPoison(m, Poison.Lethal);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class FactionGasTrapDeed : BaseFactionTrapDeed
|
||||
{
|
||||
public FactionGasTrapDeed() : base(0x11AB)
|
||||
{
|
||||
}
|
||||
|
||||
public FactionGasTrapDeed(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type TrapType => typeof(FactionGasTrap);
|
||||
public override int LabelNumber => 1044602; // faction gas trap deed
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionSawTrap : BaseFactionTrap
|
||||
{
|
||||
public FactionSawTrap(Faction f = null, Mobile m = null) : base(f, m, 0x11AC)
|
||||
{
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1041047; // faction saw trap
|
||||
|
||||
public override int AttackMessage => 1010544; // The blade cuts deep into your skin!
|
||||
public override int DisarmMessage => 1010540; // You carefully dismantle the saw mechanism and disable the trap.
|
||||
public override int EffectSound => 0x218;
|
||||
public override int MessageHue => 0x5A;
|
||||
|
||||
public override AllowedPlacing AllowedPlacing => AllowedPlacing.ControlledFactionTown;
|
||||
|
||||
public override void DoVisibleEffect()
|
||||
{
|
||||
Effects.SendLocationEffect(Location, Map, 0x11AD, 25, 10);
|
||||
}
|
||||
|
||||
public override void DoAttackEffect(Mobile m)
|
||||
{
|
||||
m.Damage(Utility.Dice(6, 10, 40), m);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class FactionSawTrapDeed : BaseFactionTrapDeed
|
||||
{
|
||||
public FactionSawTrapDeed() : base(0x1107)
|
||||
{
|
||||
}
|
||||
|
||||
public FactionSawTrapDeed(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type TrapType => typeof(FactionSawTrap);
|
||||
public override int LabelNumber => 1044604; // faction saw trap deed
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionSpikeTrap : BaseFactionTrap
|
||||
{
|
||||
public FactionSpikeTrap(Faction f = null, Mobile m = null) : base(f, m, 0x11A0)
|
||||
{
|
||||
}
|
||||
|
||||
public FactionSpikeTrap(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int LabelNumber => 1044601; // faction spike trap
|
||||
|
||||
public override int AttackMessage => 1010545; // Large spikes in the ground spring up piercing your skin!
|
||||
|
||||
public override int DisarmMessage =>
|
||||
1010541; // You carefully dismantle the trigger on the spikes and disable the trap.
|
||||
|
||||
public override int EffectSound => 0x22E;
|
||||
public override int MessageHue => 0x5A;
|
||||
|
||||
public override AllowedPlacing AllowedPlacing => AllowedPlacing.ControlledFactionTown;
|
||||
|
||||
public override void DoVisibleEffect()
|
||||
{
|
||||
Effects.SendLocationEffect(Location, Map, 0x11A4, 12, 6);
|
||||
}
|
||||
|
||||
public override void DoAttackEffect(Mobile m)
|
||||
{
|
||||
m.Damage(Utility.Dice(6, 10, 40), m);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class FactionSpikeTrapDeed : BaseFactionTrapDeed
|
||||
{
|
||||
public FactionSpikeTrapDeed() : base(0x11A5)
|
||||
{
|
||||
}
|
||||
|
||||
public FactionSpikeTrapDeed(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type TrapType => typeof(FactionSpikeTrap);
|
||||
public override int LabelNumber => 1044605; // faction spike trap deed
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
namespace Server.Factions
|
||||
{
|
||||
public class FactionTrapRemovalKit : Item
|
||||
{
|
||||
[Constructible]
|
||||
public FactionTrapRemovalKit() : base(7867)
|
||||
{
|
||||
LootType = LootType.Blessed;
|
||||
Charges = 25;
|
||||
}
|
||||
|
||||
public FactionTrapRemovalKit(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Charges{ get; set; }
|
||||
|
||||
public override int LabelNumber => 1041508; // a faction trap removal kit
|
||||
|
||||
public void ConsumeCharge(Mobile consumer)
|
||||
{
|
||||
--Charges;
|
||||
|
||||
if (Charges <= 0)
|
||||
{
|
||||
Delete();
|
||||
|
||||
consumer?.SendLocalizedMessage(1042531); // You have used all of the parts in your trap removal kit.
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetProperties(ObjectPropertyList list)
|
||||
{
|
||||
base.GetProperties(list);
|
||||
|
||||
// NOTE: OSI does not list uses remaining; intentional difference
|
||||
list.Add(1060584, Charges.ToString()); // uses remaining: ~1_val~
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(1); // version
|
||||
|
||||
writer.WriteEncodedInt(Charges);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
Charges = reader.ReadEncodedInt();
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
Charges = 25;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
107
Projects/Scripts/Engines/Factions/Mobiles/FactionWarHorse.cs
Normal file
107
Projects/Scripts/Engines/Factions/Mobiles/FactionWarHorse.cs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionWarHorse : BaseMount
|
||||
{
|
||||
public const int SilverPrice = 500;
|
||||
public const int GoldPrice = 3000;
|
||||
private Faction m_Faction;
|
||||
|
||||
public FactionWarHorse(Faction faction = null)
|
||||
: base("a war horse", 0xE2, 0x3EA0, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
BaseSoundID = 0xA8;
|
||||
|
||||
SetStr(400);
|
||||
SetDex(125);
|
||||
SetInt(51, 55);
|
||||
|
||||
SetHits(240);
|
||||
SetMana(0);
|
||||
|
||||
SetDamage(5, 8);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 100);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 40, 50);
|
||||
SetResistance(ResistanceType.Fire, 30, 40);
|
||||
SetResistance(ResistanceType.Cold, 30, 40);
|
||||
SetResistance(ResistanceType.Poison, 30, 40);
|
||||
SetResistance(ResistanceType.Energy, 30, 40);
|
||||
|
||||
SetSkill(SkillName.MagicResist, 25.1, 30.0);
|
||||
SetSkill(SkillName.Tactics, 29.3, 44.0);
|
||||
SetSkill(SkillName.Wrestling, 29.3, 44.0);
|
||||
|
||||
Fame = 300;
|
||||
Karma = 300;
|
||||
|
||||
Tamable = true;
|
||||
ControlSlots = 1;
|
||||
|
||||
Faction = faction;
|
||||
}
|
||||
|
||||
public FactionWarHorse(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override string CorpseName => "a war horse corpse";
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public Faction Faction
|
||||
{
|
||||
get => m_Faction;
|
||||
set
|
||||
{
|
||||
m_Faction = value;
|
||||
|
||||
Body = m_Faction?.Definition.WarHorseBody ?? 0xE2;
|
||||
ItemID = m_Faction?.Definition.WarHorseItem ?? 0x3EA0;
|
||||
}
|
||||
}
|
||||
|
||||
public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay;
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
PlayerState pl = PlayerState.Find(from);
|
||||
|
||||
if (pl == null)
|
||||
from.SendLocalizedMessage(1010366); // You cannot mount a faction war horse!
|
||||
else if (pl.Faction != Faction)
|
||||
from.SendLocalizedMessage(1010367); // You cannot ride an opposing faction's war horse!
|
||||
else if (pl.Rank.Rank < 2)
|
||||
from.SendLocalizedMessage(
|
||||
1010368); // You must achieve a faction rank of at least two before riding a war horse!
|
||||
else
|
||||
base.OnDoubleClick(from);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
Faction.WriteReference(writer, m_Faction);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Faction = Faction.ReadReference(reader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,528 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Factions.AI;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public abstract class BaseFactionGuard : BaseCreature
|
||||
{
|
||||
private const int ListenRange = 12;
|
||||
|
||||
private static Type[] m_StrongPotions =
|
||||
{
|
||||
typeof(GreaterHealPotion), typeof(GreaterHealPotion), typeof(GreaterHealPotion),
|
||||
typeof(GreaterCurePotion), typeof(GreaterCurePotion), typeof(GreaterCurePotion),
|
||||
typeof(GreaterStrengthPotion), typeof(GreaterStrengthPotion),
|
||||
typeof(GreaterAgilityPotion), typeof(GreaterAgilityPotion),
|
||||
typeof(TotalRefreshPotion), typeof(TotalRefreshPotion),
|
||||
typeof(GreaterExplosionPotion)
|
||||
};
|
||||
|
||||
private static Type[] m_WeakPotions =
|
||||
{
|
||||
typeof(HealPotion), typeof(HealPotion), typeof(HealPotion),
|
||||
typeof(CurePotion), typeof(CurePotion), typeof(CurePotion),
|
||||
typeof(StrengthPotion), typeof(StrengthPotion),
|
||||
typeof(AgilityPotion), typeof(AgilityPotion),
|
||||
typeof(RefreshPotion), typeof(RefreshPotion),
|
||||
typeof(ExplosionPotion)
|
||||
};
|
||||
|
||||
private Faction m_Faction;
|
||||
|
||||
private DateTime m_OrdersEnd;
|
||||
private Town m_Town;
|
||||
|
||||
public BaseFactionGuard(string title) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
Orders = new Orders(this);
|
||||
Title = title;
|
||||
|
||||
RangeHome = 6;
|
||||
}
|
||||
|
||||
public BaseFactionGuard(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool BardImmune => true;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public Faction Faction
|
||||
{
|
||||
get => m_Faction;
|
||||
set
|
||||
{
|
||||
Unregister();
|
||||
m_Faction = value;
|
||||
Register();
|
||||
}
|
||||
}
|
||||
|
||||
public Orders Orders{ get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
|
||||
public Town Town
|
||||
{
|
||||
get => m_Town;
|
||||
set
|
||||
{
|
||||
Unregister();
|
||||
m_Town = value;
|
||||
Register();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract GuardAI GuardAI{ get; }
|
||||
|
||||
protected override BaseAI ForcedAI => new FactionGuardAI(this);
|
||||
|
||||
public override TimeSpan ReacquireDelay => TimeSpan.FromSeconds(2.0);
|
||||
|
||||
public override bool ClickTitle => false;
|
||||
|
||||
public void Register()
|
||||
{
|
||||
if (m_Town != null && m_Faction != null)
|
||||
m_Town.RegisterGuard(this);
|
||||
}
|
||||
|
||||
public void Unregister()
|
||||
{
|
||||
m_Town?.UnregisterGuard(this);
|
||||
}
|
||||
|
||||
public override bool IsEnemy(Mobile m)
|
||||
{
|
||||
Faction ourFaction = m_Faction;
|
||||
Faction theirFaction = Faction.Find(m);
|
||||
|
||||
if (theirFaction == null && m is BaseFactionGuard guard)
|
||||
theirFaction = guard.Faction;
|
||||
|
||||
if (ourFaction != null && theirFaction != null && ourFaction != theirFaction)
|
||||
{
|
||||
ReactionType reactionType = Orders.GetReaction(theirFaction).Type;
|
||||
|
||||
if (reactionType == ReactionType.Attack)
|
||||
return true;
|
||||
|
||||
List<AggressorInfo> list = m.Aggressed;
|
||||
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
AggressorInfo ai = list[i];
|
||||
|
||||
if (ai.Defender is BaseFactionGuard bf && bf.Faction == ourFaction)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnMovement(Mobile m, Point3D oldLocation)
|
||||
{
|
||||
if (m.Player && m.Alive && InRange(m, 10) && !InRange(oldLocation, 10) && InLOS(m) &&
|
||||
Orders.GetReaction(Faction.Find(m)).Type == ReactionType.Warn)
|
||||
{
|
||||
Direction = GetDirectionTo(m);
|
||||
|
||||
string warning = null;
|
||||
|
||||
switch (Utility.Random(6))
|
||||
{
|
||||
case 0:
|
||||
warning =
|
||||
"I warn you, {0}, you would do well to leave this area before someone shows you the world of gray.";
|
||||
break;
|
||||
case 1:
|
||||
warning = "It would be wise to leave this area, {0}, lest your head become my commanders' trophy.";
|
||||
break;
|
||||
case 2:
|
||||
warning =
|
||||
"You are bold, {0}, for one of the meager {1}. Leave now, lest you be taught the taste of dirt.";
|
||||
break;
|
||||
case 3:
|
||||
warning = "Your presence here is an insult, {0}. Be gone now, knave.";
|
||||
break;
|
||||
case 4:
|
||||
warning = "Dost thou wish to be hung by your toes, {0}? Nay? Then come no closer.";
|
||||
break;
|
||||
case 5:
|
||||
warning = "Hey, {0}. Yeah, you. Get out of here before I beat you with a stick.";
|
||||
break;
|
||||
}
|
||||
|
||||
Faction faction = Faction.Find(m);
|
||||
|
||||
Say(warning, m.Name, faction == null ? "civilians" : faction.Definition.FriendlyName);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool HandlesOnSpeech(Mobile from)
|
||||
{
|
||||
if (InRange(from, ListenRange))
|
||||
return true;
|
||||
|
||||
return base.HandlesOnSpeech(from);
|
||||
}
|
||||
|
||||
private void ChangeReaction(Faction faction, ReactionType type)
|
||||
{
|
||||
if (faction == null)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ReactionType.Ignore:
|
||||
Say(1005179);
|
||||
break; // Civilians will now be ignored.
|
||||
case ReactionType.Warn:
|
||||
Say(1005180);
|
||||
break; // Civilians will now be warned of their impending deaths.
|
||||
case ReactionType.Attack: return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TextDefinition def = null;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ReactionType.Ignore:
|
||||
def = faction.Definition.GuardIgnore;
|
||||
break;
|
||||
case ReactionType.Warn:
|
||||
def = faction.Definition.GuardWarn;
|
||||
break;
|
||||
case ReactionType.Attack:
|
||||
def = faction.Definition.GuardAttack;
|
||||
break;
|
||||
}
|
||||
|
||||
if (def != null && def.Number > 0)
|
||||
Say(def.Number);
|
||||
else if (def?.String != null)
|
||||
Say(def.String);
|
||||
}
|
||||
|
||||
Orders.SetReaction(faction, type);
|
||||
}
|
||||
|
||||
private bool WasNamed(string speech)
|
||||
{
|
||||
string name = Name;
|
||||
|
||||
return name != null && Insensitive.StartsWith(speech, name);
|
||||
}
|
||||
|
||||
public override void OnSpeech(SpeechEventArgs e)
|
||||
{
|
||||
base.OnSpeech(e);
|
||||
|
||||
Mobile from = e.Mobile;
|
||||
|
||||
if (!e.Handled && InRange(from, ListenRange) && from.Alive)
|
||||
{
|
||||
if (e.HasKeyword(0xE6) && (Insensitive.Equals(e.Speech, "orders") || WasNamed(e.Speech))) // *orders*
|
||||
{
|
||||
if (m_Town == null || !m_Town.IsSheriff(from))
|
||||
{
|
||||
Say(1042189); // I don't work for you!
|
||||
}
|
||||
else if (Town.FromRegion(Region) == m_Town)
|
||||
{
|
||||
Say(1042180); // Your orders, sire?
|
||||
m_OrdersEnd = DateTime.UtcNow + TimeSpan.FromSeconds(10.0);
|
||||
}
|
||||
}
|
||||
else if (DateTime.UtcNow < m_OrdersEnd)
|
||||
{
|
||||
if (m_Town?.IsSheriff(from) != true || Town.FromRegion(Region) != m_Town)
|
||||
return;
|
||||
|
||||
m_OrdersEnd = DateTime.UtcNow + TimeSpan.FromSeconds(10.0);
|
||||
|
||||
bool understood = true;
|
||||
ReactionType newType = 0;
|
||||
|
||||
if (Insensitive.Contains(e.Speech, "attack"))
|
||||
newType = ReactionType.Attack;
|
||||
else if (Insensitive.Contains(e.Speech, "warn"))
|
||||
newType = ReactionType.Warn;
|
||||
else if (Insensitive.Contains(e.Speech, "ignore"))
|
||||
newType = ReactionType.Ignore;
|
||||
else
|
||||
understood = false;
|
||||
|
||||
if (understood)
|
||||
{
|
||||
understood = false;
|
||||
|
||||
if (Insensitive.Contains(e.Speech, "civil"))
|
||||
{
|
||||
ChangeReaction(null, newType);
|
||||
understood = true;
|
||||
}
|
||||
|
||||
List<Faction> factions = Faction.Factions;
|
||||
|
||||
for (int i = 0; i < factions.Count; ++i)
|
||||
{
|
||||
Faction faction = factions[i];
|
||||
|
||||
if (faction != m_Faction && Insensitive.Contains(e.Speech, faction.Definition.Keyword))
|
||||
{
|
||||
ChangeReaction(faction, newType);
|
||||
understood = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Insensitive.Contains(e.Speech, "patrol"))
|
||||
{
|
||||
Home = Location;
|
||||
RangeHome = 6;
|
||||
Combatant = null;
|
||||
Orders.Movement = MovementType.Patrol;
|
||||
Say(1005146); // This spot looks like it needs protection! I shall guard it with my life.
|
||||
understood = true;
|
||||
}
|
||||
else if (Insensitive.Contains(e.Speech, "follow"))
|
||||
{
|
||||
Home = Location;
|
||||
RangeHome = 6;
|
||||
Combatant = null;
|
||||
Orders.Follow = from;
|
||||
Orders.Movement = MovementType.Follow;
|
||||
Say(1005144); // Yes, Sire.
|
||||
understood = true;
|
||||
}
|
||||
|
||||
if (!understood)
|
||||
Say(1042183); // I'm sorry, I don't understand your orders...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetProperties(ObjectPropertyList list)
|
||||
{
|
||||
base.GetProperties(list);
|
||||
|
||||
if (m_Faction != null && Map == Faction.Facet)
|
||||
list.Add(1060846, m_Faction.Definition.PropName); // Guard: ~1_val~
|
||||
}
|
||||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
if (m_Faction != null && Map == Faction.Facet)
|
||||
{
|
||||
string text = string.Concat("(Guard, ", m_Faction.Definition.FriendlyName, ")");
|
||||
|
||||
int hue = Faction.Find(from) == m_Faction ? 98 : 38;
|
||||
|
||||
PrivateOverheadMessage(MessageType.Label, hue, true, text, from.NetState);
|
||||
}
|
||||
|
||||
base.OnSingleClick(from);
|
||||
}
|
||||
|
||||
public virtual void GenerateRandomHair()
|
||||
{
|
||||
Utility.AssignRandomHair(this);
|
||||
Utility.AssignRandomFacialHair(this, HairHue);
|
||||
}
|
||||
|
||||
public void PackStrongPotions(int min, int max)
|
||||
{
|
||||
PackStrongPotions(Utility.RandomMinMax(min, max));
|
||||
}
|
||||
|
||||
public void PackStrongPotions(int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
PackStrongPotion();
|
||||
}
|
||||
|
||||
public void PackStrongPotion()
|
||||
{
|
||||
PackItem(Loot.Construct(m_StrongPotions));
|
||||
}
|
||||
|
||||
public void PackWeakPotions(int min, int max)
|
||||
{
|
||||
PackWeakPotions(Utility.RandomMinMax(min, max));
|
||||
}
|
||||
|
||||
public void PackWeakPotions(int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
PackWeakPotion();
|
||||
}
|
||||
|
||||
public void PackWeakPotion()
|
||||
{
|
||||
PackItem(Loot.Construct(m_WeakPotions));
|
||||
}
|
||||
|
||||
public Item Immovable(Item item)
|
||||
{
|
||||
item.Movable = false;
|
||||
return item;
|
||||
}
|
||||
|
||||
public Item Newbied(Item item)
|
||||
{
|
||||
item.LootType = LootType.Newbied;
|
||||
return item;
|
||||
}
|
||||
|
||||
public Item Rehued(Item item, int hue)
|
||||
{
|
||||
item.Hue = hue;
|
||||
return item;
|
||||
}
|
||||
|
||||
public Item Layered(Item item, Layer layer)
|
||||
{
|
||||
item.Layer = layer;
|
||||
return item;
|
||||
}
|
||||
|
||||
public Item Resourced(BaseWeapon weapon, CraftResource resource)
|
||||
{
|
||||
weapon.Resource = resource;
|
||||
return weapon;
|
||||
}
|
||||
|
||||
public Item Resourced(BaseArmor armor, CraftResource resource)
|
||||
{
|
||||
armor.Resource = resource;
|
||||
return armor;
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
Unregister();
|
||||
}
|
||||
|
||||
public override void OnDeath(Container c)
|
||||
{
|
||||
base.OnDeath(c);
|
||||
|
||||
c.Delete();
|
||||
}
|
||||
|
||||
public virtual void GenerateBody(bool isFemale, bool randomHair)
|
||||
{
|
||||
Hue = Race.Human.RandomSkinHue();
|
||||
|
||||
if (isFemale)
|
||||
{
|
||||
Female = true;
|
||||
Body = 401;
|
||||
Name = NameList.RandomName("female");
|
||||
}
|
||||
else
|
||||
{
|
||||
Female = false;
|
||||
Body = 400;
|
||||
Name = NameList.RandomName("male");
|
||||
}
|
||||
|
||||
if (randomHair)
|
||||
GenerateRandomHair();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
Faction.WriteReference(writer, m_Faction);
|
||||
Town.WriteReference(writer, m_Town);
|
||||
|
||||
Orders.Serialize(writer);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
m_Faction = Faction.ReadReference(reader);
|
||||
m_Town = Town.ReadReference(reader);
|
||||
Orders = new Orders(this, reader);
|
||||
|
||||
Timer.DelayCall(TimeSpan.Zero, Register);
|
||||
}
|
||||
}
|
||||
|
||||
public class VirtualMount : IMount
|
||||
{
|
||||
private VirtualMountItem m_Item;
|
||||
|
||||
public VirtualMount(VirtualMountItem item)
|
||||
{
|
||||
m_Item = item;
|
||||
}
|
||||
|
||||
Mobile IMount.Rider
|
||||
{
|
||||
get => m_Item.Rider;
|
||||
set { }
|
||||
}
|
||||
|
||||
public virtual void OnRiderDamaged(int amount, Mobile from, bool willKill)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class VirtualMountItem : Item, IMountItem
|
||||
{
|
||||
private VirtualMount m_Mount;
|
||||
|
||||
public VirtualMountItem(Mobile mob) : base(0x3EA0)
|
||||
{
|
||||
Layer = Layer.Mount;
|
||||
|
||||
Rider = mob;
|
||||
m_Mount = new VirtualMount(this);
|
||||
}
|
||||
|
||||
public VirtualMountItem(Serial serial) : base(serial)
|
||||
{
|
||||
m_Mount = new VirtualMount(this);
|
||||
}
|
||||
|
||||
public Mobile Rider{ get; private set; }
|
||||
|
||||
public IMount Mount => m_Mount;
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(Rider);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
Rider = reader.ReadMobile();
|
||||
|
||||
if (Rider == null)
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
758
Projects/Scripts/Engines/Factions/Mobiles/Guards/GuardAI.cs
Normal file
758
Projects/Scripts/Engines/Factions/Mobiles/Guards/GuardAI.cs
Normal file
|
|
@ -0,0 +1,758 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Factions.AI;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Spells;
|
||||
using Server.Spells.Fifth;
|
||||
using Server.Spells.First;
|
||||
using Server.Spells.Fourth;
|
||||
using Server.Spells.Second;
|
||||
using Server.Spells.Seventh;
|
||||
using Server.Spells.Sixth;
|
||||
using Server.Spells.Third;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
[Flags]
|
||||
public enum GuardAI
|
||||
{
|
||||
Bless = 0x01, // heal, cure, +stats
|
||||
Curse = 0x02, // poison, -stats
|
||||
Melee = 0x04, // weapons
|
||||
Magic = 0x08, // damage spells
|
||||
Smart = 0x10 // smart weapons/damage spells
|
||||
}
|
||||
|
||||
public class ComboEntry
|
||||
{
|
||||
public ComboEntry(Type spell, int chance = 100) : this(spell, chance, TimeSpan.Zero)
|
||||
{
|
||||
}
|
||||
|
||||
public ComboEntry(Type spell, int chance, TimeSpan hold)
|
||||
{
|
||||
Spell = spell;
|
||||
Chance = chance;
|
||||
Hold = hold;
|
||||
}
|
||||
|
||||
public Type Spell{ get; }
|
||||
|
||||
public TimeSpan Hold{ get; }
|
||||
|
||||
public int Chance{ get; }
|
||||
}
|
||||
|
||||
public class SpellCombo
|
||||
{
|
||||
public static readonly SpellCombo Simple = new SpellCombo(50,
|
||||
new ComboEntry(typeof(ParalyzeSpell), 20),
|
||||
new ComboEntry(typeof(ExplosionSpell), 100, TimeSpan.FromSeconds(2.8)),
|
||||
new ComboEntry(typeof(PoisonSpell), 30),
|
||||
new ComboEntry(typeof(EnergyBoltSpell))
|
||||
);
|
||||
|
||||
public static readonly SpellCombo Strong = new SpellCombo(90,
|
||||
new ComboEntry(typeof(ParalyzeSpell), 20),
|
||||
new ComboEntry(typeof(ExplosionSpell), 50, TimeSpan.FromSeconds(2.8)),
|
||||
new ComboEntry(typeof(PoisonSpell), 30),
|
||||
new ComboEntry(typeof(ExplosionSpell), 100, TimeSpan.FromSeconds(2.8)),
|
||||
new ComboEntry(typeof(EnergyBoltSpell)),
|
||||
new ComboEntry(typeof(PoisonSpell), 30),
|
||||
new ComboEntry(typeof(EnergyBoltSpell))
|
||||
);
|
||||
|
||||
public SpellCombo(int mana, params ComboEntry[] entries)
|
||||
{
|
||||
Mana = mana;
|
||||
Entries = entries;
|
||||
}
|
||||
|
||||
public int Mana{ get; }
|
||||
|
||||
public ComboEntry[] Entries{ get; }
|
||||
|
||||
public static Spell Process(Mobile mob, Mobile targ, ref SpellCombo combo, ref int index, ref DateTime releaseTime)
|
||||
{
|
||||
while (++index < combo.Entries.Length)
|
||||
{
|
||||
ComboEntry entry = combo.Entries[index];
|
||||
|
||||
if (entry.Spell == typeof(PoisonSpell) && targ.Poisoned)
|
||||
continue;
|
||||
|
||||
if (entry.Chance > Utility.Random(100))
|
||||
{
|
||||
releaseTime = DateTime.UtcNow + entry.Hold;
|
||||
return (Spell)Activator.CreateInstance(entry.Spell, mob, null);
|
||||
}
|
||||
}
|
||||
|
||||
combo = null;
|
||||
index = -1;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class FactionGuardAI : BaseAI
|
||||
{
|
||||
private const int ManaReserve = 30;
|
||||
|
||||
private BandageContext m_Bandage;
|
||||
private DateTime m_BandageStart;
|
||||
|
||||
private SpellCombo m_Combo;
|
||||
private int m_ComboIndex = -1;
|
||||
private BaseFactionGuard m_Guard;
|
||||
private DateTime m_ReleaseTarget;
|
||||
|
||||
public FactionGuardAI(BaseFactionGuard guard) : base(guard)
|
||||
{
|
||||
m_Guard = guard;
|
||||
}
|
||||
|
||||
public bool IsDamaged => m_Guard.Hits < m_Guard.HitsMax;
|
||||
|
||||
public bool IsPoisoned => m_Guard.Poisoned;
|
||||
|
||||
public TimeSpan TimeUntilBandage
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Bandage != null && m_Bandage.Timer == null)
|
||||
m_Bandage = null;
|
||||
|
||||
if (m_Bandage == null)
|
||||
return TimeSpan.MaxValue;
|
||||
|
||||
TimeSpan ts = m_BandageStart + m_Bandage.Timer.Delay - DateTime.UtcNow;
|
||||
|
||||
if (ts < TimeSpan.FromSeconds(-1.0))
|
||||
{
|
||||
m_Bandage = null;
|
||||
return TimeSpan.MaxValue;
|
||||
}
|
||||
|
||||
if (ts < TimeSpan.Zero)
|
||||
ts = TimeSpan.Zero;
|
||||
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAllowed(GuardAI flag)
|
||||
{
|
||||
return (m_Guard.GuardAI & flag) == flag;
|
||||
}
|
||||
|
||||
public bool DequipWeapon()
|
||||
{
|
||||
Container pack = m_Guard.Backpack;
|
||||
|
||||
if (pack == null)
|
||||
return false;
|
||||
|
||||
if (m_Guard.Weapon is Item weapon && weapon.Parent == m_Guard && !(weapon is Fists))
|
||||
{
|
||||
pack.DropItem(weapon);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool EquipWeapon()
|
||||
{
|
||||
Item weapon = m_Guard.Backpack?.FindItemByType<BaseWeapon>();
|
||||
|
||||
return weapon != null && m_Guard.EquipItem(weapon);
|
||||
}
|
||||
|
||||
public bool StartBandage()
|
||||
{
|
||||
m_Bandage = null;
|
||||
|
||||
if (m_Guard.Backpack?.FindItemByType<Bandage>() == null)
|
||||
return false;
|
||||
|
||||
m_Bandage = BandageContext.BeginHeal(m_Guard, m_Guard);
|
||||
m_BandageStart = DateTime.UtcNow;
|
||||
return m_Bandage != null;
|
||||
}
|
||||
|
||||
public bool UseItemByType(Type type)
|
||||
{
|
||||
Container pack = m_Guard.Backpack;
|
||||
|
||||
Item item = pack?.FindItemByType(type);
|
||||
|
||||
if (item == null)
|
||||
return false;
|
||||
|
||||
bool requip = DequipWeapon();
|
||||
|
||||
item.OnDoubleClick(m_Guard);
|
||||
|
||||
if (requip)
|
||||
EquipWeapon();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int GetStatMod(Mobile mob, StatType type)
|
||||
{
|
||||
StatMod mod = mob.GetStatMod($"[Magic] {type} Offset");
|
||||
|
||||
if (mod == null)
|
||||
return 0;
|
||||
|
||||
return mod.Offset;
|
||||
}
|
||||
|
||||
public Spell RandomOffenseSpell()
|
||||
{
|
||||
int maxCircle = (int)((m_Guard.Skills.Magery.Value + 20.0) / (100.0 / 7.0));
|
||||
|
||||
if (maxCircle < 1)
|
||||
maxCircle = 1;
|
||||
|
||||
switch (Utility.Random(maxCircle * 2))
|
||||
{
|
||||
case 0:
|
||||
case 1: return new MagicArrowSpell(m_Guard);
|
||||
case 2:
|
||||
case 3: return new HarmSpell(m_Guard);
|
||||
case 4:
|
||||
case 5: return new FireballSpell(m_Guard);
|
||||
case 6:
|
||||
case 7: return new LightningSpell(m_Guard);
|
||||
case 8: return new MindBlastSpell(m_Guard);
|
||||
case 9: return new ParalyzeSpell(m_Guard);
|
||||
case 10: return new EnergyBoltSpell(m_Guard);
|
||||
case 11: return new ExplosionSpell(m_Guard);
|
||||
default: return new FlameStrikeSpell(m_Guard);
|
||||
}
|
||||
}
|
||||
|
||||
public Mobile FindDispelTarget(bool activeOnly)
|
||||
{
|
||||
if (m_Mobile.Deleted || m_Mobile.Int < 95 || CanDispel(m_Mobile) || m_Mobile.AutoDispel)
|
||||
return null;
|
||||
|
||||
if (activeOnly)
|
||||
{
|
||||
List<AggressorInfo> aggressed = m_Mobile.Aggressed;
|
||||
List<AggressorInfo> aggressors = m_Mobile.Aggressors;
|
||||
|
||||
Mobile active = null;
|
||||
double activePrio = 0.0;
|
||||
|
||||
Mobile comb = m_Mobile.Combatant;
|
||||
|
||||
if (comb?.Deleted == false && comb.Alive && !comb.IsDeadBondedPet && m_Mobile.InRange(comb, 12) &&
|
||||
CanDispel(comb))
|
||||
{
|
||||
active = comb;
|
||||
activePrio = m_Mobile.GetDistanceToSqrt(comb);
|
||||
|
||||
if (activePrio <= 2)
|
||||
return active;
|
||||
}
|
||||
|
||||
for (int i = 0; i < aggressed.Count; ++i)
|
||||
{
|
||||
AggressorInfo info = aggressed[i];
|
||||
Mobile m = info.Defender;
|
||||
|
||||
if (m != comb && m.Combatant == m_Mobile && m_Mobile.InRange(m, 12) && CanDispel(m))
|
||||
{
|
||||
double prio = m_Mobile.GetDistanceToSqrt(m);
|
||||
|
||||
if (active == null || prio < activePrio)
|
||||
{
|
||||
active = m;
|
||||
activePrio = prio;
|
||||
|
||||
if (activePrio <= 2)
|
||||
return active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < aggressors.Count; ++i)
|
||||
{
|
||||
AggressorInfo info = aggressors[i];
|
||||
Mobile m = info.Attacker;
|
||||
|
||||
if (m != comb && m.Combatant == m_Mobile && m_Mobile.InRange(m, 12) && CanDispel(m))
|
||||
{
|
||||
double prio = m_Mobile.GetDistanceToSqrt(m);
|
||||
|
||||
if (active == null || prio < activePrio)
|
||||
{
|
||||
active = m;
|
||||
activePrio = prio;
|
||||
|
||||
if (activePrio <= 2)
|
||||
return active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return active;
|
||||
}
|
||||
|
||||
Map map = m_Mobile.Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
Mobile active = null, inactive = null;
|
||||
double actPrio = 0.0, inactPrio = 0.0;
|
||||
|
||||
Mobile comb = m_Mobile.Combatant;
|
||||
|
||||
if (comb?.Deleted == false && comb.Alive && !comb.IsDeadBondedPet && CanDispel(comb))
|
||||
{
|
||||
active = inactive = comb;
|
||||
actPrio = inactPrio = m_Mobile.GetDistanceToSqrt(comb);
|
||||
}
|
||||
|
||||
foreach (Mobile m in m_Mobile.GetMobilesInRange(12))
|
||||
if (m != m_Mobile && CanDispel(m))
|
||||
{
|
||||
double prio = m_Mobile.GetDistanceToSqrt(m);
|
||||
|
||||
if (inactive == null || prio < inactPrio)
|
||||
{
|
||||
inactive = m;
|
||||
inactPrio = prio;
|
||||
}
|
||||
|
||||
if ((m_Mobile.Combatant == m || m.Combatant == m_Mobile) && (active == null || prio < actPrio))
|
||||
{
|
||||
active = m;
|
||||
actPrio = prio;
|
||||
}
|
||||
}
|
||||
|
||||
return active ?? inactive;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool CanDispel(Mobile m)
|
||||
{
|
||||
return m is BaseCreature creature && creature.Summoned && m_Mobile.CanBeHarmful(creature, false) &&
|
||||
!creature.IsAnimatedDead;
|
||||
}
|
||||
|
||||
public void RunTo(Mobile m)
|
||||
{
|
||||
/*if ( m.Paralyzed || m.Frozen )
|
||||
{
|
||||
if ( m_Mobile.InRange( m, 1 ) )
|
||||
RunFrom( m );
|
||||
else if ( !m_Mobile.InRange( m, m_Mobile.RangeFight > 2 ? m_Mobile.RangeFight : 2 ) && !MoveTo( m, true, 1 ) )
|
||||
OnFailedMove();
|
||||
}
|
||||
else
|
||||
{*/
|
||||
if (!m_Mobile.InRange(m, m_Mobile.RangeFight))
|
||||
{
|
||||
if (!MoveTo(m, true, 1))
|
||||
OnFailedMove();
|
||||
}
|
||||
else if (m_Mobile.InRange(m, m_Mobile.RangeFight - 1))
|
||||
{
|
||||
RunFrom(m);
|
||||
}
|
||||
|
||||
/*}*/
|
||||
}
|
||||
|
||||
public void RunFrom(Mobile m)
|
||||
{
|
||||
Run((m_Mobile.GetDirectionTo(m) - 4) & Direction.Mask);
|
||||
}
|
||||
|
||||
public void OnFailedMove()
|
||||
{
|
||||
/*if ( !m_Mobile.DisallowAllMoves && 20 > Utility.Random( 100 ) && IsAllowed( GuardAI.Magic ) )
|
||||
{
|
||||
if ( m_Mobile.Target != null )
|
||||
m_Mobile.Target.Cancel( m_Mobile, TargetCancelType.Canceled );
|
||||
|
||||
new TeleportSpell( m_Mobile, null ).Cast();
|
||||
|
||||
m_Mobile.DebugSay( "I am stuck, I'm going to try teleporting away" );
|
||||
}
|
||||
else*/
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
if (m_Mobile.Debug)
|
||||
m_Mobile.DebugSay("My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I am stuck");
|
||||
}
|
||||
}
|
||||
|
||||
public void Run(Direction d)
|
||||
{
|
||||
if (m_Mobile.Spell != null && m_Mobile.Spell.IsCasting || m_Mobile.Paralyzed || m_Mobile.Frozen ||
|
||||
m_Mobile.DisallowAllMoves)
|
||||
return;
|
||||
|
||||
m_Mobile.Direction = d | Direction.Running;
|
||||
|
||||
if (!DoMove(m_Mobile.Direction, true))
|
||||
OnFailedMove();
|
||||
}
|
||||
|
||||
public override bool Think()
|
||||
{
|
||||
if (m_Mobile.Deleted)
|
||||
return false;
|
||||
|
||||
Mobile combatant = m_Guard.Combatant;
|
||||
|
||||
if (combatant?.Deleted != false || !combatant.Alive || combatant.IsDeadBondedPet ||
|
||||
!m_Mobile.CanSee(combatant) || !m_Mobile.CanBeHarmful(combatant, false) || combatant.Map != m_Mobile.Map)
|
||||
{
|
||||
// Our combatant is deleted, dead, hidden, or we cannot hurt them
|
||||
// Try to find another combatant
|
||||
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.Combatant = combatant = m_Mobile.FocusMob;
|
||||
m_Mobile.FocusMob = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.Combatant = combatant = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (combatant != null && (!m_Mobile.InLOS(combatant) || !m_Mobile.InRange(combatant, 12)))
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.Combatant = combatant = m_Mobile.FocusMob;
|
||||
m_Mobile.FocusMob = null;
|
||||
}
|
||||
else if (!m_Mobile.InRange(combatant, 36))
|
||||
{
|
||||
m_Mobile.Combatant = combatant = null;
|
||||
}
|
||||
}
|
||||
|
||||
Mobile dispelTarget = FindDispelTarget(true);
|
||||
|
||||
if (m_Guard.Target != null && m_ReleaseTarget == DateTime.MinValue)
|
||||
m_ReleaseTarget = DateTime.UtcNow + TimeSpan.FromSeconds(10.0);
|
||||
|
||||
if (m_Guard.Target != null && DateTime.UtcNow > m_ReleaseTarget)
|
||||
{
|
||||
Target targ = m_Guard.Target;
|
||||
|
||||
Mobile toHarm = dispelTarget ?? combatant;
|
||||
|
||||
if ((targ.Flags & TargetFlags.Harmful) != 0 && toHarm != null)
|
||||
{
|
||||
if (m_Guard.Map == toHarm.Map && (targ.Range < 0 || m_Guard.InRange(toHarm, targ.Range)) &&
|
||||
m_Guard.CanSee(toHarm) && m_Guard.InLOS(toHarm))
|
||||
targ.Invoke(m_Guard, toHarm);
|
||||
else if ((targ as ISpellTarget)?.Spell is DispelSpell)
|
||||
targ.Cancel(m_Guard, TargetCancelType.Canceled);
|
||||
}
|
||||
else if ((targ.Flags & TargetFlags.Beneficial) != 0)
|
||||
{
|
||||
targ.Invoke(m_Guard, m_Guard);
|
||||
}
|
||||
else
|
||||
{
|
||||
targ.Cancel(m_Guard, TargetCancelType.Canceled);
|
||||
}
|
||||
|
||||
m_ReleaseTarget = DateTime.MinValue;
|
||||
}
|
||||
|
||||
if (dispelTarget != null)
|
||||
{
|
||||
if (Action != ActionType.Combat)
|
||||
Action = ActionType.Combat;
|
||||
|
||||
m_Guard.Warmode = true;
|
||||
|
||||
RunFrom(dispelTarget);
|
||||
}
|
||||
else if (combatant != null)
|
||||
{
|
||||
if (Action != ActionType.Combat)
|
||||
Action = ActionType.Combat;
|
||||
|
||||
m_Guard.Warmode = true;
|
||||
|
||||
RunTo(combatant);
|
||||
}
|
||||
else if (m_Guard.Orders.Movement != MovementType.Stand)
|
||||
{
|
||||
Mobile toFollow = null;
|
||||
|
||||
if (m_Guard.Town != null && m_Guard.Orders.Movement == MovementType.Follow)
|
||||
{
|
||||
toFollow = m_Guard.Orders.Follow ?? m_Guard.Town.Sheriff;
|
||||
}
|
||||
|
||||
if (toFollow != null && toFollow.Map == m_Guard.Map &&
|
||||
toFollow.InRange(m_Guard, m_Guard.RangePerception * 3) &&
|
||||
Town.FromRegion(toFollow.Region) == m_Guard.Town)
|
||||
{
|
||||
if (Action != ActionType.Combat)
|
||||
Action = ActionType.Combat;
|
||||
|
||||
if (m_Mobile.CurrentSpeed != m_Mobile.ActiveSpeed)
|
||||
m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed;
|
||||
|
||||
m_Guard.Warmode = true;
|
||||
|
||||
RunTo(toFollow);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Action != ActionType.Wander)
|
||||
Action = ActionType.Wander;
|
||||
|
||||
if (m_Mobile.CurrentSpeed != m_Mobile.PassiveSpeed)
|
||||
m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed;
|
||||
|
||||
m_Guard.Warmode = false;
|
||||
|
||||
WalkRandomInHome(2, 2, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Action != ActionType.Wander)
|
||||
Action = ActionType.Wander;
|
||||
|
||||
m_Guard.Warmode = false;
|
||||
}
|
||||
|
||||
if ((IsDamaged || IsPoisoned) && m_Guard.Skills.Healing.Base > 20.0)
|
||||
{
|
||||
TimeSpan ts = TimeUntilBandage;
|
||||
|
||||
if (ts == TimeSpan.MaxValue)
|
||||
StartBandage();
|
||||
}
|
||||
|
||||
Spell spell = m_Mobile.Spell as Spell;
|
||||
|
||||
if (spell == null && Core.TickCount - m_Mobile.NextSpellTime >= 0)
|
||||
{
|
||||
DateTime toRelease = DateTime.MinValue;
|
||||
|
||||
if (IsPoisoned)
|
||||
{
|
||||
Poison p = m_Guard.Poison;
|
||||
|
||||
TimeSpan ts = TimeUntilBandage;
|
||||
|
||||
if (p != Poison.Lesser || ts == TimeSpan.MaxValue || TimeUntilBandage < TimeSpan.FromSeconds(1.5) ||
|
||||
m_Guard.HitsMax - m_Guard.Hits > Utility.Random(250))
|
||||
{
|
||||
if (IsAllowed(GuardAI.Bless))
|
||||
spell = new CureSpell(m_Guard);
|
||||
else
|
||||
UseItemByType(typeof(BaseCurePotion));
|
||||
}
|
||||
}
|
||||
else if (IsDamaged && m_Guard.HitsMax - m_Guard.Hits > Utility.Random(200))
|
||||
{
|
||||
if (IsAllowed(GuardAI.Magic) && m_Guard.Hits * 100 / Math.Max(m_Guard.HitsMax, 1) < 10 &&
|
||||
m_Guard.Home != Point3D.Zero && !Utility.InRange(m_Guard.Location, m_Guard.Home, 15) &&
|
||||
m_Guard.Mana >= 11)
|
||||
{
|
||||
spell = new RecallSpell(m_Guard,
|
||||
new RunebookEntry(m_Guard.Home, m_Guard.Map, "Guard's Home"));
|
||||
}
|
||||
else if (IsAllowed(GuardAI.Bless))
|
||||
{
|
||||
if (m_Guard.Mana >= 11 && m_Guard.Hits + 30 < m_Guard.HitsMax)
|
||||
spell = new GreaterHealSpell(m_Guard);
|
||||
else if (m_Guard.Hits + 10 < m_Guard.HitsMax &&
|
||||
(m_Guard.Mana < 11 || m_Guard.NextCombatTime - Core.TickCount > 2000))
|
||||
spell = new HealSpell(m_Guard);
|
||||
}
|
||||
else if (m_Guard.CanBeginAction<BaseHealPotion>())
|
||||
{
|
||||
UseItemByType(typeof(BaseHealPotion));
|
||||
}
|
||||
}
|
||||
else if (dispelTarget != null &&
|
||||
(IsAllowed(GuardAI.Magic) || IsAllowed(GuardAI.Bless) || IsAllowed(GuardAI.Curse)))
|
||||
{
|
||||
if (!dispelTarget.Paralyzed && m_Guard.Mana > ManaReserve + 20 && 40 > Utility.Random(100))
|
||||
spell = new ParalyzeSpell(m_Guard);
|
||||
else
|
||||
spell = new DispelSpell(m_Guard);
|
||||
}
|
||||
|
||||
if (combatant != null)
|
||||
{
|
||||
if (m_Combo != null)
|
||||
{
|
||||
if (spell == null)
|
||||
{
|
||||
spell = SpellCombo.Process(m_Guard, combatant, ref m_Combo, ref m_ComboIndex, ref toRelease);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Combo = null;
|
||||
m_ComboIndex = -1;
|
||||
}
|
||||
}
|
||||
else if (20 > Utility.Random(100) && IsAllowed(GuardAI.Magic))
|
||||
{
|
||||
if (80 > Utility.Random(100))
|
||||
{
|
||||
m_Combo = IsAllowed(GuardAI.Smart) ? SpellCombo.Simple : SpellCombo.Strong;
|
||||
m_ComboIndex = -1;
|
||||
|
||||
if (m_Guard.Mana >= ManaReserve + m_Combo.Mana)
|
||||
{
|
||||
spell = SpellCombo.Process(m_Guard, combatant, ref m_Combo, ref m_ComboIndex, ref toRelease);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Combo = null;
|
||||
|
||||
if (m_Guard.Mana >= ManaReserve + 40)
|
||||
spell = RandomOffenseSpell();
|
||||
}
|
||||
}
|
||||
else if (m_Guard.Mana >= ManaReserve + 40)
|
||||
{
|
||||
spell = RandomOffenseSpell();
|
||||
}
|
||||
}
|
||||
|
||||
if (spell == null && 2 > Utility.Random(100) && m_Guard.Mana >= ManaReserve + 10)
|
||||
{
|
||||
int strMod = GetStatMod(m_Guard, StatType.Str);
|
||||
int dexMod = GetStatMod(m_Guard, StatType.Dex);
|
||||
int intMod = GetStatMod(m_Guard, StatType.Int);
|
||||
|
||||
List<Type> types = new List<Type>();
|
||||
|
||||
if (strMod <= 0)
|
||||
types.Add(typeof(StrengthSpell));
|
||||
|
||||
if (dexMod <= 0 && IsAllowed(GuardAI.Melee))
|
||||
types.Add(typeof(AgilitySpell));
|
||||
|
||||
if (intMod <= 0 && IsAllowed(GuardAI.Magic))
|
||||
types.Add(typeof(CunningSpell));
|
||||
|
||||
if (IsAllowed(GuardAI.Bless))
|
||||
{
|
||||
if (types.Count > 1)
|
||||
spell = new BlessSpell(m_Guard);
|
||||
else if (types.Count == 1)
|
||||
spell = Activator.CreateInstance(types[0], m_Guard, null) as Spell;
|
||||
}
|
||||
else if (types.Count > 0)
|
||||
{
|
||||
if (types[0] == typeof(StrengthSpell))
|
||||
UseItemByType(typeof(BaseStrengthPotion));
|
||||
else if (types[0] == typeof(AgilitySpell))
|
||||
UseItemByType(typeof(BaseAgilityPotion));
|
||||
}
|
||||
}
|
||||
|
||||
if (spell == null && 2 > Utility.Random(100) && m_Guard.Mana >= ManaReserve + 10 &&
|
||||
IsAllowed(GuardAI.Curse))
|
||||
{
|
||||
if (!combatant.Poisoned && 40 > Utility.Random(100))
|
||||
{
|
||||
spell = new PoisonSpell(m_Guard);
|
||||
}
|
||||
else
|
||||
{
|
||||
int strMod = GetStatMod(combatant, StatType.Str);
|
||||
int dexMod = GetStatMod(combatant, StatType.Dex);
|
||||
int intMod = GetStatMod(combatant, StatType.Int);
|
||||
|
||||
List<Type> types = new List<Type>();
|
||||
|
||||
if (strMod >= 0)
|
||||
types.Add(typeof(WeakenSpell));
|
||||
|
||||
if (dexMod >= 0 && IsAllowed(GuardAI.Melee))
|
||||
types.Add(typeof(ClumsySpell));
|
||||
|
||||
if (intMod >= 0 && IsAllowed(GuardAI.Magic))
|
||||
types.Add(typeof(FeeblemindSpell));
|
||||
|
||||
if (types.Count > 1)
|
||||
spell = new CurseSpell(m_Guard);
|
||||
else if (types.Count == 1)
|
||||
spell = (Spell)Activator.CreateInstance(types[0], m_Guard, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (spell != null && m_Guard.HitsMax - m_Guard.Hits + 10 > Utility.Random(100))
|
||||
{
|
||||
Type type = null;
|
||||
|
||||
if (spell is GreaterHealSpell)
|
||||
type = typeof(BaseHealPotion);
|
||||
else if (spell is CureSpell)
|
||||
type = typeof(BaseCurePotion);
|
||||
else if (spell is StrengthSpell)
|
||||
type = typeof(BaseStrengthPotion);
|
||||
else if (spell is AgilitySpell)
|
||||
type = typeof(BaseAgilityPotion);
|
||||
|
||||
if (type == typeof(BaseHealPotion) && !m_Guard.CanBeginAction(type))
|
||||
type = null;
|
||||
|
||||
if (type != null && m_Guard.Target == null && UseItemByType(type))
|
||||
{
|
||||
if (spell is GreaterHealSpell)
|
||||
{
|
||||
if (m_Guard.Hits + 30 > m_Guard.HitsMax && m_Guard.Hits + 10 < m_Guard.HitsMax)
|
||||
spell = new HealSpell(m_Guard);
|
||||
}
|
||||
else
|
||||
{
|
||||
spell = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (spell == null && m_Guard.Stam < m_Guard.StamMax / 3 && IsAllowed(GuardAI.Melee))
|
||||
{
|
||||
UseItemByType(typeof(BaseRefreshPotion));
|
||||
}
|
||||
|
||||
if (spell?.Cast() != true)
|
||||
EquipWeapon();
|
||||
}
|
||||
else if (spell?.State == SpellState.Sequencing)
|
||||
{
|
||||
EquipWeapon();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
141
Projects/Scripts/Engines/Factions/Mobiles/Guards/Orders.cs
Normal file
141
Projects/Scripts/Engines/Factions/Mobiles/Guards/Orders.cs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Factions.AI
|
||||
{
|
||||
public enum ReactionType
|
||||
{
|
||||
Ignore,
|
||||
Warn,
|
||||
Attack
|
||||
}
|
||||
|
||||
public enum MovementType
|
||||
{
|
||||
Stand,
|
||||
Patrol,
|
||||
Follow
|
||||
}
|
||||
|
||||
public class Reaction
|
||||
{
|
||||
public Reaction(Faction faction, ReactionType type)
|
||||
{
|
||||
Faction = faction;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public Reaction(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Faction = Faction.ReadReference(reader);
|
||||
Type = (ReactionType)reader.ReadEncodedInt();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Faction Faction{ get; }
|
||||
|
||||
public ReactionType Type{ get; set; }
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(0); // version
|
||||
|
||||
Faction.WriteReference(writer, Faction);
|
||||
writer.WriteEncodedInt((int)Type);
|
||||
}
|
||||
}
|
||||
|
||||
public class Orders
|
||||
{
|
||||
private List<Reaction> m_Reactions;
|
||||
|
||||
public Orders(BaseFactionGuard guard)
|
||||
{
|
||||
Guard = guard;
|
||||
m_Reactions = new List<Reaction>();
|
||||
Movement = MovementType.Patrol;
|
||||
}
|
||||
|
||||
public Orders(BaseFactionGuard guard, GenericReader reader)
|
||||
{
|
||||
Guard = guard;
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
Follow = reader.ReadMobile();
|
||||
goto case 0;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
int count = reader.ReadEncodedInt();
|
||||
m_Reactions = new List<Reaction>(count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
m_Reactions.Add(new Reaction(reader));
|
||||
|
||||
Movement = (MovementType)reader.ReadEncodedInt();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BaseFactionGuard Guard{ get; }
|
||||
|
||||
public MovementType Movement{ get; set; }
|
||||
|
||||
public Mobile Follow{ get; set; }
|
||||
|
||||
public Reaction GetReaction(Faction faction)
|
||||
{
|
||||
Reaction reaction;
|
||||
|
||||
for (int i = 0; i < m_Reactions.Count; ++i)
|
||||
{
|
||||
reaction = m_Reactions[i];
|
||||
|
||||
if (reaction.Faction == faction)
|
||||
return reaction;
|
||||
}
|
||||
|
||||
reaction = new Reaction(faction,
|
||||
faction == null || faction == Guard.Faction ? ReactionType.Ignore : ReactionType.Attack);
|
||||
m_Reactions.Add(reaction);
|
||||
|
||||
return reaction;
|
||||
}
|
||||
|
||||
public void SetReaction(Faction faction, ReactionType type)
|
||||
{
|
||||
Reaction reaction = GetReaction(faction);
|
||||
|
||||
reaction.Type = type;
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(1); // version
|
||||
|
||||
writer.Write(Follow);
|
||||
|
||||
writer.WriteEncodedInt(m_Reactions.Count);
|
||||
|
||||
for (int i = 0; i < m_Reactions.Count; ++i)
|
||||
m_Reactions[i].Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt((int)Movement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
using Server.Items;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionBerserker : BaseFactionGuard
|
||||
{
|
||||
[Constructible]
|
||||
public FactionBerserker() : base("the berserker")
|
||||
{
|
||||
GenerateBody(false, false);
|
||||
|
||||
SetStr(126, 150);
|
||||
SetDex(61, 85);
|
||||
SetInt(81, 95);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 100);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 30, 50);
|
||||
SetResistance(ResistanceType.Fire, 30, 50);
|
||||
SetResistance(ResistanceType.Cold, 30, 50);
|
||||
SetResistance(ResistanceType.Energy, 30, 50);
|
||||
SetResistance(ResistanceType.Poison, 30, 50);
|
||||
|
||||
VirtualArmor = 24;
|
||||
|
||||
SetSkill(SkillName.Swords, 100.0, 110.0);
|
||||
SetSkill(SkillName.Wrestling, 100.0, 110.0);
|
||||
SetSkill(SkillName.Tactics, 100.0, 110.0);
|
||||
SetSkill(SkillName.MagicResist, 100.0, 110.0);
|
||||
SetSkill(SkillName.Healing, 100.0, 110.0);
|
||||
SetSkill(SkillName.Anatomy, 100.0, 110.0);
|
||||
|
||||
SetSkill(SkillName.Magery, 100.0, 110.0);
|
||||
SetSkill(SkillName.EvalInt, 100.0, 110.0);
|
||||
SetSkill(SkillName.Meditation, 100.0, 110.0);
|
||||
|
||||
AddItem(Immovable(Rehued(new BodySash(), 1645)));
|
||||
AddItem(Immovable(Rehued(new Kilt(), 1645)));
|
||||
AddItem(Immovable(Rehued(new Sandals(), 1645)));
|
||||
AddItem(Newbied(new DoubleAxe()));
|
||||
|
||||
HairItemID = 0x2047; // Afro
|
||||
HairHue = 0x29;
|
||||
|
||||
FacialHairItemID = 0x204B; // Medium Short Beard
|
||||
FacialHairHue = 0x29;
|
||||
|
||||
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
|
||||
PackStrongPotions(6, 12);
|
||||
}
|
||||
|
||||
public FactionBerserker(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override GuardAI GuardAI => GuardAI.Melee | GuardAI.Curse | GuardAI.Bless;
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
using Server.Items;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionDeathKnight : BaseFactionGuard
|
||||
{
|
||||
[Constructible]
|
||||
public FactionDeathKnight() : base("the death knight")
|
||||
{
|
||||
GenerateBody(false, false);
|
||||
Hue = 1;
|
||||
|
||||
SetStr(126, 150);
|
||||
SetDex(61, 85);
|
||||
SetInt(81, 95);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 100);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 30, 50);
|
||||
SetResistance(ResistanceType.Fire, 30, 50);
|
||||
SetResistance(ResistanceType.Cold, 30, 50);
|
||||
SetResistance(ResistanceType.Energy, 30, 50);
|
||||
SetResistance(ResistanceType.Poison, 30, 50);
|
||||
|
||||
VirtualArmor = 24;
|
||||
|
||||
SetSkill(SkillName.Swords, 100.0, 110.0);
|
||||
SetSkill(SkillName.Wrestling, 100.0, 110.0);
|
||||
SetSkill(SkillName.Tactics, 100.0, 110.0);
|
||||
SetSkill(SkillName.MagicResist, 100.0, 110.0);
|
||||
SetSkill(SkillName.Healing, 100.0, 110.0);
|
||||
SetSkill(SkillName.Anatomy, 100.0, 110.0);
|
||||
|
||||
SetSkill(SkillName.Magery, 100.0, 110.0);
|
||||
SetSkill(SkillName.EvalInt, 100.0, 110.0);
|
||||
SetSkill(SkillName.Meditation, 100.0, 110.0);
|
||||
|
||||
Item shroud = new Item(0x204E);
|
||||
shroud.Layer = Layer.OuterTorso;
|
||||
|
||||
AddItem(Immovable(Rehued(shroud, 1109)));
|
||||
AddItem(Newbied(Rehued(new ExecutionersAxe(), 2211)));
|
||||
|
||||
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
|
||||
PackStrongPotions(6, 12);
|
||||
}
|
||||
|
||||
public FactionDeathKnight(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override GuardAI GuardAI => GuardAI.Melee | GuardAI.Curse | GuardAI.Bless;
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
using Server.Items;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionDragoon : BaseFactionGuard
|
||||
{
|
||||
[Constructible]
|
||||
public FactionDragoon() : base("the dragoon")
|
||||
{
|
||||
GenerateBody(false, false);
|
||||
|
||||
SetStr(151, 175);
|
||||
SetDex(61, 85);
|
||||
SetInt(151, 175);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 40, 60);
|
||||
SetResistance(ResistanceType.Fire, 40, 60);
|
||||
SetResistance(ResistanceType.Cold, 40, 60);
|
||||
SetResistance(ResistanceType.Energy, 40, 60);
|
||||
SetResistance(ResistanceType.Poison, 40, 60);
|
||||
|
||||
VirtualArmor = 32;
|
||||
|
||||
SetSkill(SkillName.Macing, 110.0, 120.0);
|
||||
SetSkill(SkillName.Wrestling, 110.0, 120.0);
|
||||
SetSkill(SkillName.Tactics, 110.0, 120.0);
|
||||
SetSkill(SkillName.MagicResist, 110.0, 120.0);
|
||||
SetSkill(SkillName.Healing, 110.0, 120.0);
|
||||
SetSkill(SkillName.Anatomy, 110.0, 120.0);
|
||||
|
||||
SetSkill(SkillName.Magery, 110.0, 120.0);
|
||||
SetSkill(SkillName.EvalInt, 110.0, 120.0);
|
||||
SetSkill(SkillName.Meditation, 110.0, 120.0);
|
||||
|
||||
AddItem(Immovable(Rehued(new Cloak(), 1645)));
|
||||
|
||||
AddItem(Immovable(Rehued(new PlateChest(), 1645)));
|
||||
AddItem(Immovable(Rehued(new PlateLegs(), 1109)));
|
||||
AddItem(Immovable(Rehued(new PlateArms(), 1109)));
|
||||
AddItem(Immovable(Rehued(new PlateGloves(), 1109)));
|
||||
AddItem(Immovable(Rehued(new PlateGorget(), 1109)));
|
||||
AddItem(Immovable(Rehued(new PlateHelm(), 1109)));
|
||||
|
||||
AddItem(Newbied(new WarHammer()));
|
||||
|
||||
AddItem(Immovable(Rehued(new VirtualMountItem(this), 1109)));
|
||||
|
||||
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
|
||||
PackStrongPotions(6, 12);
|
||||
}
|
||||
|
||||
public FactionDragoon(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override GuardAI GuardAI => GuardAI.Magic | GuardAI.Melee | GuardAI.Smart | GuardAI.Bless | GuardAI.Curse;
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
using Server.Items;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionHenchman : BaseFactionGuard
|
||||
{
|
||||
[Constructible]
|
||||
public FactionHenchman() : base("the henchman")
|
||||
{
|
||||
GenerateBody(false, true);
|
||||
|
||||
SetStr(91, 115);
|
||||
SetDex(61, 85);
|
||||
SetInt(81, 95);
|
||||
|
||||
SetDamage(10, 14);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 10, 30);
|
||||
SetResistance(ResistanceType.Fire, 10, 30);
|
||||
SetResistance(ResistanceType.Cold, 10, 30);
|
||||
SetResistance(ResistanceType.Energy, 10, 30);
|
||||
SetResistance(ResistanceType.Poison, 10, 30);
|
||||
|
||||
VirtualArmor = 8;
|
||||
|
||||
SetSkill(SkillName.Fencing, 80.0, 90.0);
|
||||
SetSkill(SkillName.Wrestling, 80.0, 90.0);
|
||||
SetSkill(SkillName.Tactics, 80.0, 90.0);
|
||||
SetSkill(SkillName.MagicResist, 80.0, 90.0);
|
||||
SetSkill(SkillName.Healing, 80.0, 90.0);
|
||||
SetSkill(SkillName.Anatomy, 80.0, 90.0);
|
||||
|
||||
AddItem(new StuddedChest());
|
||||
AddItem(new StuddedLegs());
|
||||
AddItem(new StuddedArms());
|
||||
AddItem(new StuddedGloves());
|
||||
AddItem(new StuddedGorget());
|
||||
AddItem(new Boots());
|
||||
AddItem(Newbied(new Spear()));
|
||||
|
||||
PackItem(new Bandage(Utility.RandomMinMax(10, 20)));
|
||||
PackWeakPotions(1, 4);
|
||||
}
|
||||
|
||||
public FactionHenchman(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override GuardAI GuardAI => GuardAI.Melee;
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
using Server.Items;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionKnight : BaseFactionGuard
|
||||
{
|
||||
[Constructible]
|
||||
public FactionKnight() : base("the knight")
|
||||
{
|
||||
GenerateBody(false, false);
|
||||
|
||||
SetStr(126, 150);
|
||||
SetDex(61, 85);
|
||||
SetInt(81, 95);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 100);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 30, 50);
|
||||
SetResistance(ResistanceType.Fire, 30, 50);
|
||||
SetResistance(ResistanceType.Cold, 30, 50);
|
||||
SetResistance(ResistanceType.Energy, 30, 50);
|
||||
SetResistance(ResistanceType.Poison, 30, 50);
|
||||
|
||||
VirtualArmor = 24;
|
||||
|
||||
SetSkill(SkillName.Swords, 100.0, 110.0);
|
||||
SetSkill(SkillName.Wrestling, 100.0, 110.0);
|
||||
SetSkill(SkillName.Tactics, 100.0, 110.0);
|
||||
SetSkill(SkillName.MagicResist, 100.0, 110.0);
|
||||
SetSkill(SkillName.Healing, 100.0, 110.0);
|
||||
SetSkill(SkillName.Anatomy, 100.0, 110.0);
|
||||
|
||||
SetSkill(SkillName.Magery, 100.0, 110.0);
|
||||
SetSkill(SkillName.EvalInt, 100.0, 110.0);
|
||||
SetSkill(SkillName.Meditation, 100.0, 110.0);
|
||||
|
||||
AddItem(Immovable(Rehued(new ChainChest(), 2125)));
|
||||
AddItem(Immovable(Rehued(new ChainLegs(), 2125)));
|
||||
AddItem(Immovable(Rehued(new ChainCoif(), 2125)));
|
||||
AddItem(Immovable(Rehued(new PlateArms(), 2125)));
|
||||
AddItem(Immovable(Rehued(new PlateGloves(), 2125)));
|
||||
|
||||
AddItem(Immovable(Rehued(new BodySash(), 1254)));
|
||||
AddItem(Immovable(Rehued(new Kilt(), 1254)));
|
||||
AddItem(Immovable(Rehued(new Sandals(), 1254)));
|
||||
|
||||
AddItem(Newbied(new Bardiche()));
|
||||
|
||||
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
|
||||
PackStrongPotions(6, 12);
|
||||
}
|
||||
|
||||
public FactionKnight(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override GuardAI GuardAI => GuardAI.Magic | GuardAI.Melee | GuardAI.Smart | GuardAI.Curse | GuardAI.Bless;
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
using Server.Items;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionMercenary : BaseFactionGuard
|
||||
{
|
||||
[Constructible]
|
||||
public FactionMercenary() : base("the mercenary")
|
||||
{
|
||||
GenerateBody(false, true);
|
||||
|
||||
SetStr(116, 125);
|
||||
SetDex(61, 85);
|
||||
SetInt(81, 95);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 20, 40);
|
||||
SetResistance(ResistanceType.Fire, 20, 40);
|
||||
SetResistance(ResistanceType.Cold, 20, 40);
|
||||
SetResistance(ResistanceType.Energy, 20, 40);
|
||||
SetResistance(ResistanceType.Poison, 20, 40);
|
||||
|
||||
VirtualArmor = 16;
|
||||
|
||||
SetSkill(SkillName.Fencing, 90.0, 100.0);
|
||||
SetSkill(SkillName.Wrestling, 90.0, 100.0);
|
||||
SetSkill(SkillName.Tactics, 90.0, 100.0);
|
||||
SetSkill(SkillName.MagicResist, 90.0, 100.0);
|
||||
SetSkill(SkillName.Healing, 90.0, 100.0);
|
||||
SetSkill(SkillName.Anatomy, 90.0, 100.0);
|
||||
|
||||
AddItem(new ChainChest());
|
||||
AddItem(new ChainLegs());
|
||||
AddItem(new RingmailArms());
|
||||
AddItem(new RingmailGloves());
|
||||
AddItem(new ChainCoif());
|
||||
AddItem(new Boots());
|
||||
AddItem(Newbied(new ShortSpear()));
|
||||
|
||||
PackItem(new Bandage(Utility.RandomMinMax(20, 30)));
|
||||
PackStrongPotions(3, 8);
|
||||
}
|
||||
|
||||
public FactionMercenary(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override GuardAI GuardAI => GuardAI.Melee | GuardAI.Smart;
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
using Server.Items;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionNecromancer : BaseFactionGuard
|
||||
{
|
||||
[Constructible]
|
||||
public FactionNecromancer() : base("the necromancer")
|
||||
{
|
||||
GenerateBody(false, false);
|
||||
Hue = 1;
|
||||
|
||||
SetStr(151, 175);
|
||||
SetDex(61, 85);
|
||||
SetInt(151, 175);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 40, 60);
|
||||
SetResistance(ResistanceType.Fire, 40, 60);
|
||||
SetResistance(ResistanceType.Cold, 40, 60);
|
||||
SetResistance(ResistanceType.Energy, 40, 60);
|
||||
SetResistance(ResistanceType.Poison, 40, 60);
|
||||
|
||||
VirtualArmor = 32;
|
||||
|
||||
SetSkill(SkillName.Macing, 110.0, 120.0);
|
||||
SetSkill(SkillName.Wrestling, 110.0, 120.0);
|
||||
SetSkill(SkillName.Tactics, 110.0, 120.0);
|
||||
SetSkill(SkillName.MagicResist, 110.0, 120.0);
|
||||
SetSkill(SkillName.Healing, 110.0, 120.0);
|
||||
SetSkill(SkillName.Anatomy, 110.0, 120.0);
|
||||
|
||||
SetSkill(SkillName.Magery, 110.0, 120.0);
|
||||
SetSkill(SkillName.EvalInt, 110.0, 120.0);
|
||||
SetSkill(SkillName.Meditation, 110.0, 120.0);
|
||||
|
||||
Item shroud = new Item(0x204E);
|
||||
shroud.Layer = Layer.OuterTorso;
|
||||
|
||||
AddItem(Immovable(Rehued(shroud, 1109)));
|
||||
AddItem(Newbied(Rehued(new GnarledStaff(), 2211)));
|
||||
|
||||
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
|
||||
PackStrongPotions(6, 12);
|
||||
}
|
||||
|
||||
public FactionNecromancer(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override GuardAI GuardAI => GuardAI.Magic | GuardAI.Smart | GuardAI.Bless | GuardAI.Curse;
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
using Server.Items;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionPaladin : BaseFactionGuard
|
||||
{
|
||||
[Constructible]
|
||||
public FactionPaladin() : base("the paladin")
|
||||
{
|
||||
GenerateBody(false, false);
|
||||
|
||||
SetStr(151, 175);
|
||||
SetDex(61, 85);
|
||||
SetInt(81, 95);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 40, 60);
|
||||
SetResistance(ResistanceType.Fire, 40, 60);
|
||||
SetResistance(ResistanceType.Cold, 40, 60);
|
||||
SetResistance(ResistanceType.Energy, 40, 60);
|
||||
SetResistance(ResistanceType.Poison, 40, 60);
|
||||
|
||||
VirtualArmor = 32;
|
||||
|
||||
SetSkill(SkillName.Swords, 110.0, 120.0);
|
||||
SetSkill(SkillName.Wrestling, 110.0, 120.0);
|
||||
SetSkill(SkillName.Tactics, 110.0, 120.0);
|
||||
SetSkill(SkillName.MagicResist, 110.0, 120.0);
|
||||
SetSkill(SkillName.Healing, 110.0, 120.0);
|
||||
SetSkill(SkillName.Anatomy, 110.0, 120.0);
|
||||
|
||||
SetSkill(SkillName.Magery, 110.0, 120.0);
|
||||
SetSkill(SkillName.EvalInt, 110.0, 120.0);
|
||||
SetSkill(SkillName.Meditation, 110.0, 120.0);
|
||||
|
||||
AddItem(Immovable(Rehued(new PlateChest(), 2125)));
|
||||
AddItem(Immovable(Rehued(new PlateLegs(), 2125)));
|
||||
AddItem(Immovable(Rehued(new PlateHelm(), 2125)));
|
||||
AddItem(Immovable(Rehued(new PlateGorget(), 2125)));
|
||||
AddItem(Immovable(Rehued(new PlateArms(), 2125)));
|
||||
AddItem(Immovable(Rehued(new PlateGloves(), 2125)));
|
||||
|
||||
AddItem(Immovable(Rehued(new BodySash(), 1254)));
|
||||
AddItem(Immovable(Rehued(new Cloak(), 1254)));
|
||||
|
||||
AddItem(Newbied(new Halberd()));
|
||||
|
||||
AddItem(Immovable(Rehued(new VirtualMountItem(this), 1254)));
|
||||
|
||||
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
|
||||
PackStrongPotions(6, 12);
|
||||
}
|
||||
|
||||
public FactionPaladin(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override GuardAI GuardAI => GuardAI.Magic | GuardAI.Melee | GuardAI.Smart | GuardAI.Curse | GuardAI.Bless;
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
using Server.Items;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionSorceress : BaseFactionGuard
|
||||
{
|
||||
[Constructible]
|
||||
public FactionSorceress() : base("the sorceress")
|
||||
{
|
||||
GenerateBody(true, false);
|
||||
|
||||
SetStr(126, 150);
|
||||
SetDex(61, 85);
|
||||
SetInt(126, 150);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 100);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 30, 50);
|
||||
SetResistance(ResistanceType.Fire, 30, 50);
|
||||
SetResistance(ResistanceType.Cold, 30, 50);
|
||||
SetResistance(ResistanceType.Energy, 30, 50);
|
||||
SetResistance(ResistanceType.Poison, 30, 50);
|
||||
|
||||
VirtualArmor = 24;
|
||||
|
||||
SetSkill(SkillName.Macing, 100.0, 110.0);
|
||||
SetSkill(SkillName.Wrestling, 100.0, 110.0);
|
||||
SetSkill(SkillName.Tactics, 100.0, 110.0);
|
||||
SetSkill(SkillName.MagicResist, 100.0, 110.0);
|
||||
SetSkill(SkillName.Healing, 100.0, 110.0);
|
||||
SetSkill(SkillName.Anatomy, 100.0, 110.0);
|
||||
|
||||
SetSkill(SkillName.Magery, 100.0, 110.0);
|
||||
SetSkill(SkillName.EvalInt, 100.0, 110.0);
|
||||
SetSkill(SkillName.Meditation, 100.0, 110.0);
|
||||
|
||||
AddItem(Immovable(Rehued(new WizardsHat(), 1325)));
|
||||
AddItem(Immovable(Rehued(new Sandals(), 1325)));
|
||||
AddItem(Immovable(Rehued(new LeatherGorget(), 1325)));
|
||||
AddItem(Immovable(Rehued(new LeatherGloves(), 1325)));
|
||||
AddItem(Immovable(Rehued(new LeatherLegs(), 1325)));
|
||||
AddItem(Immovable(Rehued(new Skirt(), 1325)));
|
||||
AddItem(Immovable(Rehued(new FemaleLeatherChest(), 1325)));
|
||||
AddItem(Newbied(Rehued(new QuarterStaff(), 1310)));
|
||||
|
||||
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
|
||||
PackStrongPotions(6, 12);
|
||||
}
|
||||
|
||||
public FactionSorceress(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override GuardAI GuardAI => GuardAI.Magic | GuardAI.Bless | GuardAI.Curse;
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
using Server.Items;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionWizard : BaseFactionGuard
|
||||
{
|
||||
[Constructible]
|
||||
public FactionWizard() : base("the wizard")
|
||||
{
|
||||
GenerateBody(false, false);
|
||||
|
||||
SetStr(151, 175);
|
||||
SetDex(61, 85);
|
||||
SetInt(151, 175);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 100);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 40, 60);
|
||||
SetResistance(ResistanceType.Fire, 40, 60);
|
||||
SetResistance(ResistanceType.Cold, 40, 60);
|
||||
SetResistance(ResistanceType.Energy, 40, 60);
|
||||
SetResistance(ResistanceType.Poison, 40, 60);
|
||||
|
||||
VirtualArmor = 32;
|
||||
|
||||
SetSkill(SkillName.Macing, 110.0, 120.0);
|
||||
SetSkill(SkillName.Wrestling, 110.0, 120.0);
|
||||
SetSkill(SkillName.Tactics, 110.0, 120.0);
|
||||
SetSkill(SkillName.MagicResist, 110.0, 120.0);
|
||||
SetSkill(SkillName.Healing, 110.0, 120.0);
|
||||
SetSkill(SkillName.Anatomy, 110.0, 120.0);
|
||||
|
||||
SetSkill(SkillName.Magery, 110.0, 120.0);
|
||||
SetSkill(SkillName.EvalInt, 110.0, 120.0);
|
||||
SetSkill(SkillName.Meditation, 110.0, 120.0);
|
||||
|
||||
AddItem(Immovable(Rehued(new WizardsHat(), 1325)));
|
||||
AddItem(Immovable(Rehued(new Sandals(), 1325)));
|
||||
AddItem(Immovable(Rehued(new Robe(), 1310)));
|
||||
AddItem(Immovable(Rehued(new LeatherGloves(), 1325)));
|
||||
AddItem(Newbied(Rehued(new GnarledStaff(), 1310)));
|
||||
|
||||
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
|
||||
PackStrongPotions(6, 12);
|
||||
}
|
||||
|
||||
public FactionWizard(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override GuardAI GuardAI => GuardAI.Magic | GuardAI.Smart | GuardAI.Bless | GuardAI.Curse;
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public abstract class BaseFactionVendor : BaseVendor
|
||||
{
|
||||
private Faction m_Faction;
|
||||
private Town m_Town;
|
||||
|
||||
public BaseFactionVendor(Town town, Faction faction, string title) : base(title)
|
||||
{
|
||||
Frozen = true;
|
||||
CantWalk = true;
|
||||
Female = false;
|
||||
BodyValue = 400;
|
||||
Name = NameList.RandomName("male");
|
||||
|
||||
RangeHome = 0;
|
||||
|
||||
m_Town = town;
|
||||
m_Faction = faction;
|
||||
Register();
|
||||
}
|
||||
|
||||
public BaseFactionVendor(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public Town Town
|
||||
{
|
||||
get => m_Town;
|
||||
set
|
||||
{
|
||||
Unregister();
|
||||
m_Town = value;
|
||||
Register();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
|
||||
public Faction Faction
|
||||
{
|
||||
get => m_Faction;
|
||||
set
|
||||
{
|
||||
Unregister();
|
||||
m_Faction = value;
|
||||
Register();
|
||||
}
|
||||
}
|
||||
|
||||
protected override List<SBInfo> SBInfos{ get; } = new List<SBInfo>();
|
||||
|
||||
public void Register()
|
||||
{
|
||||
if (m_Town != null && m_Faction != null)
|
||||
m_Town.RegisterVendor(this);
|
||||
}
|
||||
|
||||
public override bool OnMoveOver(Mobile m)
|
||||
{
|
||||
if (Core.ML)
|
||||
return true;
|
||||
|
||||
return base.OnMoveOver(m);
|
||||
}
|
||||
|
||||
public void Unregister()
|
||||
{
|
||||
m_Town?.UnregisterVendor(this);
|
||||
}
|
||||
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
|
||||
Unregister();
|
||||
}
|
||||
|
||||
public override bool CheckVendorAccess(Mobile from)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
Town.WriteReference(writer, m_Town);
|
||||
Faction.WriteReference(writer, m_Faction);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Town = Town.ReadReference(reader);
|
||||
m_Faction = Faction.ReadReference(reader);
|
||||
Register();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Frozen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionBoardVendor : BaseFactionVendor
|
||||
{
|
||||
public FactionBoardVendor(Town town, Faction faction) :
|
||||
base(town, faction, "the LumberMan") // NOTE: title inconsistant, as OSI
|
||||
{
|
||||
SetSkill(SkillName.Carpentry, 85.0, 100.0);
|
||||
SetSkill(SkillName.Lumberjacking, 60.0, 83.0);
|
||||
}
|
||||
|
||||
public FactionBoardVendor(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
SBInfos.Add(new SBFactionBoard());
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
base.InitOutfit();
|
||||
|
||||
AddItem(new HalfApron());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class SBFactionBoard : SBInfo
|
||||
{
|
||||
public override IShopSellInfo SellInfo{ get; } = new InternalSellInfo();
|
||||
|
||||
public override List<GenericBuyInfo> BuyInfo{ get; } = new InternalBuyInfo();
|
||||
|
||||
public class InternalBuyInfo : List<GenericBuyInfo>
|
||||
{
|
||||
public InternalBuyInfo()
|
||||
{
|
||||
for (int i = 0; i < 5; ++i)
|
||||
Add(new GenericBuyInfo(typeof(Board), 3, 20, 0x1BD7, 0));
|
||||
}
|
||||
}
|
||||
|
||||
public class InternalSellInfo : GenericSellInfo
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionBottleVendor : BaseFactionVendor
|
||||
{
|
||||
public FactionBottleVendor(Town town, Faction faction) : base(town, faction, "the Bottle Seller")
|
||||
{
|
||||
SetSkill(SkillName.Alchemy, 85.0, 100.0);
|
||||
SetSkill(SkillName.TasteID, 65.0, 88.0);
|
||||
}
|
||||
|
||||
public FactionBottleVendor(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals;
|
||||
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
SBInfos.Add(new SBFactionBottle());
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
base.InitOutfit();
|
||||
|
||||
AddItem(new Robe(Utility.RandomPinkHue()));
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class SBFactionBottle : SBInfo
|
||||
{
|
||||
public override IShopSellInfo SellInfo{ get; } = new InternalSellInfo();
|
||||
|
||||
public override List<GenericBuyInfo> BuyInfo{ get; } = new InternalBuyInfo();
|
||||
|
||||
public class InternalBuyInfo : List<GenericBuyInfo>
|
||||
{
|
||||
public InternalBuyInfo()
|
||||
{
|
||||
for (int i = 0; i < 5; ++i)
|
||||
Add(new GenericBuyInfo(typeof(Bottle), 5, 20, 0xF0E, 0));
|
||||
}
|
||||
}
|
||||
|
||||
public class InternalSellInfo : GenericSellInfo
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionHorseVendor : BaseFactionVendor
|
||||
{
|
||||
public FactionHorseVendor(Town town, Faction faction) : base(town, faction, "the Horse Breeder")
|
||||
{
|
||||
SetSkill(SkillName.AnimalLore, 64.0, 100.0);
|
||||
SetSkill(SkillName.AnimalTaming, 90.0, 100.0);
|
||||
SetSkill(SkillName.Veterinary, 65.0, 88.0);
|
||||
}
|
||||
|
||||
public FactionHorseVendor(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override VendorShoeType ShoeType => Female ? VendorShoeType.ThighBoots : VendorShoeType.Boots;
|
||||
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public override int GetShoeHue()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
base.InitOutfit();
|
||||
|
||||
AddItem(Utility.RandomBool() ? new QuarterStaff() : (Item)new ShepherdsCrook());
|
||||
}
|
||||
|
||||
public override void VendorBuy(Mobile from)
|
||||
{
|
||||
if (Faction == null || Faction.Find(from, true) != Faction)
|
||||
PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042201,
|
||||
from.NetState); // You are not in my faction, I cannot sell you a horse!
|
||||
else if (FactionGump.Exists(from))
|
||||
from.SendLocalizedMessage(1042160); // You already have a faction menu open.
|
||||
else if (from is PlayerMobile mobile)
|
||||
mobile.SendGump(new HorseBreederGump(mobile, Faction));
|
||||
}
|
||||
|
||||
public override void VendorSell(Mobile from)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool OnBuyItems(Mobile buyer, List<BuyItemResponse> list)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool OnSellItems(Mobile seller, List<SellItemResponse> list)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionOreVendor : BaseFactionVendor
|
||||
{
|
||||
public FactionOreVendor(Town town, Faction faction) : base(town, faction, "the Ore Man")
|
||||
{
|
||||
// NOTE: Skills verified
|
||||
SetSkill(SkillName.Carpentry, 85.0, 100.0);
|
||||
SetSkill(SkillName.Lumberjacking, 60.0, 83.0);
|
||||
}
|
||||
|
||||
public FactionOreVendor(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
SBInfos.Add(new SBFactionOre());
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
base.InitOutfit();
|
||||
|
||||
AddItem(new HalfApron());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class SBFactionOre : SBInfo
|
||||
{
|
||||
private static readonly object[] m_FixedSizeArgs = { true };
|
||||
|
||||
public override IShopSellInfo SellInfo{ get; } = new InternalSellInfo();
|
||||
|
||||
public override List<GenericBuyInfo> BuyInfo{ get; } = new InternalBuyInfo();
|
||||
|
||||
public class InternalBuyInfo : List<GenericBuyInfo>
|
||||
{
|
||||
public InternalBuyInfo()
|
||||
{
|
||||
for (int i = 0; i < 5; ++i)
|
||||
Add(new GenericBuyInfo(typeof(IronOre), 16, 20, 0x19B8, 0, m_FixedSizeArgs));
|
||||
}
|
||||
}
|
||||
|
||||
public class InternalSellInfo : GenericSellInfo
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Factions
|
||||
{
|
||||
public class FactionReagentVendor : BaseFactionVendor
|
||||
{
|
||||
public FactionReagentVendor(Town town, Faction faction) : base(town, faction, "the Reagent Man")
|
||||
{
|
||||
SetSkill(SkillName.EvalInt, 65.0, 88.0);
|
||||
SetSkill(SkillName.Inscribe, 60.0, 83.0);
|
||||
SetSkill(SkillName.Magery, 64.0, 100.0);
|
||||
SetSkill(SkillName.Meditation, 60.0, 83.0);
|
||||
SetSkill(SkillName.MagicResist, 65.0, 88.0);
|
||||
SetSkill(SkillName.Wrestling, 36.0, 68.0);
|
||||
}
|
||||
|
||||
public FactionReagentVendor(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals;
|
||||
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
SBInfos.Add(new SBFactionReagent());
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
base.InitOutfit();
|
||||
|
||||
AddItem(new Robe(Utility.RandomBlueHue()));
|
||||
AddItem(new GnarledStaff());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class SBFactionReagent : SBInfo
|
||||
{
|
||||
public override IShopSellInfo SellInfo{ get; } = new InternalSellInfo();
|
||||
|
||||
public override List<GenericBuyInfo> BuyInfo{ get; } = new InternalBuyInfo();
|
||||
|
||||
public class InternalBuyInfo : List<GenericBuyInfo>
|
||||
{
|
||||
public InternalBuyInfo()
|
||||
{
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
Add(new GenericBuyInfo(typeof(BlackPearl), 5, 20, 0xF7A, 0));
|
||||
Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 20, 0xF7B, 0));
|
||||
Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 20, 0xF86, 0));
|
||||
Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0));
|
||||
Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0));
|
||||
Add(new GenericBuyInfo(typeof(Nightshade), 3, 20, 0xF88, 0));
|
||||
Add(new GenericBuyInfo(typeof(SpidersSilk), 3, 20, 0xF8D, 0));
|
||||
Add(new GenericBuyInfo(typeof(SulfurousAsh), 3, 20, 0xF8C, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class InternalSellInfo : GenericSellInfo
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue