using System; using System.Collections; using System.Collections.Generic; using Server.Accounting; using Server.Commands; using Server.Commands.Generic; using Server.Guilds; using Server.Items; using Server.Mobiles; using Server.Prompts; using Server.Targeting; namespace Server.Factions { public static class Settings { public static bool NewCoMLocation { get; private set; } public static bool Enabled { get; private set; } public static List FactionsDisabledNotice; public static void AddDisabledNotice(Mobile m) { if (FactionsDisabledNotice == null) { FactionsDisabledNotice = new List(); FactionsDisabledNotice.Add(m); } else if(!FactionsDisabledNotice.Contains(m)) { FactionsDisabledNotice.Add(m); } } public static void Serialize(GenericWriter writer) { writer.Write(0); writer.Write(FactionsDisabledNotice == null ? 0 : FactionsDisabledNotice.Count); if (FactionsDisabledNotice != null) { for (int i = 0; i < FactionsDisabledNotice.Count; i++) { writer.Write(FactionsDisabledNotice[i]); } } } public static void Deserlialize(GenericReader reader) { int version = reader.ReadInt(); int count = reader.ReadInt(); for (int i = 0; i < count; i++) { Mobile m = reader.ReadMobile(); if (m != null) { AddDisabledNotice(m); } } } public static void OnLogin(LoginEventArgs e) { Mobile m = e.Mobile; if (FactionsDisabledNotice != null && FactionsDisabledNotice.Contains(m)) { Timer.DelayCall(TimeSpan.FromSeconds(2), () => { m.SendGump(new Server.Gumps.BasicInfoGump(1155489)); /*Notice: The faction system has been replaced with the Vice vs Virtue system. We invite you to check out * this new and exciting PvP experience! As a result some items including Greater Stamina Potions, Supernova * Potions, Shrine Gems, Faction Stronghold Runes, and Cloaks of Command have been removed from your * inventory. Some of these items are available from participating in Vice vs Virtue. You can join Vice * vs Virtue by clicking on "Join Vice vs Virtue" from the front page of the guild menu.*/ FactionsDisabledNotice.Remove(m); }); } } public static void Configure() { NewCoMLocation = Config.Get("Factions.NewCoMLocation", true); Enabled = !Server.Engines.VvV.ViceVsVirtueSystem.Enabled; EventSink.Login += OnLogin; /* Disabling Factions: * PlayerStates are not loaded, ie faction players lose their faction status * Factions/Towns are still serialized, so if factions were ever re-enabled, the town, tithe rate, etc would be the same * stronghold regions are not registered for free movement for non-factions */ } } [CustomEnum(new string[] { "Minax", "Council of Mages", "True Britannians", "Shadowlords" })] public abstract class Faction : IComparable { public int ZeroRankOffset; private FactionDefinition m_Definition; private FactionState m_State; private StrongholdRegion m_StrongholdRegion; public StrongholdRegion StrongholdRegion { get { return this.m_StrongholdRegion; } set { this.m_StrongholdRegion = value; } } public FactionDefinition Definition { get { return this.m_Definition; } set { this.m_Definition = value; if(Settings.Enabled) this.m_StrongholdRegion = new StrongholdRegion(this); } } public FactionState State { get { return this.m_State; } set { this.m_State = value; } } public Election Election { get { return this.m_State.Election; } set { this.m_State.Election = value; } } public Mobile Commander { get { return this.m_State.Commander; } set { this.m_State.Commander = value; } } public int Tithe { get { return this.m_State.Tithe; } set { this.m_State.Tithe = value; } } public int Silver { get { return this.m_State.Silver; } set { this.m_State.Silver = value; } } public List Members { get { return this.m_State.Members; } set { this.m_State.Members = value; } } public static readonly TimeSpan LeavePeriod = TimeSpan.FromDays(3.0); public bool FactionMessageReady { get { return this.m_State.FactionMessageReady; } } public void Broadcast(string text) { this.Broadcast(0x3B2, text); } public void Broadcast(int hue, string text) { List members = this.Members; for (int i = 0; i < members.Count; ++i) members[i].Mobile.SendMessage(hue, text); } public void Broadcast(int number) { List members = this.Members; for (int i = 0; i < members.Count; ++i) members[i].Mobile.SendLocalizedMessage(number); } public void Broadcast(string format, params object[] args) { this.Broadcast(String.Format(format, args)); } public void Broadcast(int hue, string format, params object[] args) { this.Broadcast(hue, String.Format(format, args)); } public void BeginBroadcast(Mobile from) { from.SendLocalizedMessage(1010265); // Enter Faction Message from.Prompt = new BroadcastPrompt(this); } public void EndBroadcast(Mobile from, string text) { if (from.IsPlayer()) this.m_State.RegisterBroadcast(); this.Broadcast(this.Definition.HueBroadcast, "{0} [Commander] {1} : {2}", from.Name, this.Definition.FriendlyName, text); } private class BroadcastPrompt : Prompt { private readonly Faction m_Faction; public BroadcastPrompt(Faction faction) { this.m_Faction = faction; } public override void OnResponse(Mobile from, string text) { this.m_Faction.EndBroadcast(from, text); } } public static void HandleAtrophy() { foreach (Faction f in Factions) { if (!f.State.IsAtrophyReady) return; } List activePlayers = new List(); foreach (Faction f in Factions) { foreach (PlayerState ps in f.Members) { if (ps.KillPoints > 0 && ps.IsActive) activePlayers.Add(ps); } } int distrib = 0; foreach (Faction f in Factions) distrib += f.State.CheckAtrophy(); if (activePlayers.Count == 0) return; for (int i = 0; i < distrib; ++i) activePlayers[Utility.Random(activePlayers.Count)].KillPoints++; } public static void DistributePoints(int distrib) { List activePlayers = new List(); foreach (Faction f in Factions) { foreach (PlayerState ps in f.Members) { if (ps.KillPoints > 0 && ps.IsActive) { activePlayers.Add(ps); } } } if (activePlayers.Count > 0) { for (int i = 0; i < distrib; ++i) { activePlayers[Utility.Random(activePlayers.Count)].KillPoints++; } } } public void BeginHonorLeadership(Mobile from) { from.SendLocalizedMessage(502090); // Click on the player whom you wish to honor. from.BeginTarget(12, false, TargetFlags.None, new TargetCallback(HonorLeadership_OnTarget)); } public void HonorLeadership_OnTarget(Mobile from, object obj) { if (obj is Mobile) { Mobile recv = (Mobile)obj; PlayerState giveState = PlayerState.Find(from); PlayerState recvState = PlayerState.Find(recv); if (giveState == null) return; if (recvState == null || recvState.Faction != giveState.Faction) { from.SendLocalizedMessage(1042497); // Only faction mates can be honored this way. } else if (giveState.KillPoints < 5) { from.SendLocalizedMessage(1042499); // You must have at least five kill points to honor them. } else { recvState.LastHonorTime = DateTime.UtcNow; giveState.KillPoints -= 5; recvState.KillPoints += 4; // TODO: Confirm no message sent to giver recv.SendLocalizedMessage(1042500); // You have been honored with four kill points. } } else { from.SendLocalizedMessage(1042496); // You may only honor another player. } } public virtual void AddMember(Mobile mob) { this.Members.Insert(this.ZeroRankOffset, new PlayerState(mob, this, this.Members)); mob.AddToBackpack(FactionItem.Imbue(new Robe(), this, false, this.Definition.HuePrimary)); mob.SendLocalizedMessage(1010374); // You have been granted a robe which signifies your faction mob.InvalidateProperties(); mob.Delta(MobileDelta.Noto); mob.FixedEffect(0x373A, 10, 30); mob.PlaySound(0x209); } public static bool IsNearType(Mobile mob, Type type, int range) { bool mobs = type.IsSubclassOf(typeof(Mobile)); bool items = type.IsSubclassOf(typeof(Item)); IPooledEnumerable eable; if (mobs) eable = mob.GetMobilesInRange(range); else if (items) eable = mob.GetItemsInRange(range); else return false; foreach (object obj in eable) { if (type.IsAssignableFrom(obj.GetType())) { eable.Free(); return true; } } eable.Free(); return false; } public static bool IsNearType(Mobile mob, Type[] types, int range) { IPooledEnumerable eable = mob.GetObjectsInRange(range); foreach (object obj in eable) { Type objType = obj.GetType(); for (int i = 0; i < types.Length; i++) { if (types[i].IsAssignableFrom(objType)) { eable.Free(); return true; } } } eable.Free(); return false; } public void RemovePlayerState(PlayerState pl) { if (pl == null || !this.Members.Contains(pl)) return; int killPoints = pl.KillPoints; if (pl.RankIndex != -1) { while ((pl.RankIndex + 1) < this.ZeroRankOffset) { PlayerState pNext = this.Members[pl.RankIndex + 1] as PlayerState; this.Members[pl.RankIndex + 1] = pl; this.Members[pl.RankIndex] = pNext; pl.RankIndex++; pNext.RankIndex--; } this.ZeroRankOffset--; } this.Members.Remove(pl); PlayerMobile pm = (PlayerMobile)pl.Mobile; if (pm == null) return; Mobile mob = pl.Mobile; if (pm.FactionPlayerState == pl) { pm.FactionPlayerState = null; mob.InvalidateProperties(); mob.Delta(MobileDelta.Noto); if (this.Election.IsCandidate(mob)) this.Election.RemoveCandidate(mob); if (pl.Finance != null) pl.Finance.Finance = null; if (pl.Sheriff != null) pl.Sheriff.Sheriff = null; this.Election.RemoveVoter(mob); if (this.Commander == mob) this.Commander = null; pm.ValidateEquipment(); } if (killPoints > 0) DistributePoints(killPoints); } public void RemoveMember(Mobile mob) { PlayerState pl = PlayerState.Find(mob); if (pl == null || !this.Members.Contains(pl)) return; int killPoints = pl.KillPoints; if (mob.Backpack != null) { //Ordinarily, through normal faction removal, this will never find any sigils. //Only with a leave delay less than the ReturnPeriod or a Faction Kick/Ban, will this ever do anything Item[] sigils = mob.Backpack.FindItemsByType(typeof(Sigil)); for (int i = 0; i < sigils.Length; ++i) ((Sigil)sigils[i]).ReturnHome(); } if (pl.RankIndex != -1) { while ((pl.RankIndex + 1) < this.ZeroRankOffset) { PlayerState pNext = this.Members[pl.RankIndex + 1]; this.Members[pl.RankIndex + 1] = pl; this.Members[pl.RankIndex] = pNext; pl.RankIndex++; pNext.RankIndex--; } this.ZeroRankOffset--; } this.Members.Remove(pl); if (mob is PlayerMobile) ((PlayerMobile)mob).FactionPlayerState = null; mob.InvalidateProperties(); mob.Delta(MobileDelta.Noto); if (this.Election.IsCandidate(mob)) this.Election.RemoveCandidate(mob); this.Election.RemoveVoter(mob); if (pl.Finance != null) pl.Finance.Finance = null; if (pl.Sheriff != null) pl.Sheriff.Sheriff = null; if (this.Commander == mob) this.Commander = null; if (mob is PlayerMobile) ((PlayerMobile)mob).ValidateEquipment(); if (killPoints > 0) DistributePoints(killPoints); } public void JoinGuilded(PlayerMobile mob, Guild guild) { if (mob.Young) { guild.RemoveMember(mob); mob.SendLocalizedMessage(1042283); // You have been kicked out of your guild! Young players may not remain in a guild which is allied with a faction. } else if (this.AlreadyHasCharInFaction(mob)) { guild.RemoveMember(mob); mob.SendLocalizedMessage(1005281); // You have been kicked out of your guild due to factional overlap } else if (IsFactionBanned(mob)) { guild.RemoveMember(mob); mob.SendLocalizedMessage(1005052); // You are currently banned from the faction system } else { this.AddMember(mob); mob.SendLocalizedMessage(1042756, true, " " + this.m_Definition.FriendlyName); // You are now joining a faction: } } public void JoinAlone(Mobile mob) { this.AddMember(mob); mob.SendLocalizedMessage(1005058); // You have joined the faction } private bool AlreadyHasCharInFaction(Mobile mob) { Account acct = mob.Account as Account; if (acct != null) { for (int i = 0; i < acct.Length; ++i) { Mobile c = acct[i]; if (Find(c) != null) return true; } } return false; } public static bool IsFactionBanned(Mobile mob) { Account acct = mob.Account as Account; if (acct == null) return false; return (acct.GetTag("FactionBanned") != null); } public void OnJoinAccepted(Mobile mob) { PlayerMobile pm = mob as PlayerMobile; if (pm == null) return; // sanity PlayerState pl = PlayerState.Find(pm); if (pm.Young) pm.SendLocalizedMessage(1010104); // You cannot join a faction as a young player else if (pl != null && pl.IsLeaving) pm.SendLocalizedMessage(1005051); // You cannot use the faction stone until you have finished quitting your current faction else if (this.AlreadyHasCharInFaction(pm)) pm.SendLocalizedMessage(1005059); // You cannot join a faction because you already declared your allegiance with another character else if (IsFactionBanned(mob)) pm.SendLocalizedMessage(1005052); // You are currently banned from the faction system else if (pm.Guild != null) { Guild guild = pm.Guild as Guild; if (guild.Leader != pm) pm.SendLocalizedMessage(1005057); // You cannot join a faction because you are in a guild and not the guildmaster else if (!Guild.NewGuildSystem && guild.Type != GuildType.Regular) pm.SendLocalizedMessage(1042161); // You cannot join a faction because your guild is an Order or Chaos type. else if (!Guild.NewGuildSystem && guild.Enemies != null && guild.Enemies.Count > 0) //CAN join w/wars in new system pm.SendLocalizedMessage(1005056); // You cannot join a faction with active Wars else if (Guild.NewGuildSystem && guild.Alliance != null) pm.SendLocalizedMessage(1080454); // Your guild cannot join a faction while in alliance with non-factioned guilds. else if (!this.CanHandleInflux(guild.Members.Count)) pm.SendLocalizedMessage(1018031); // In the interest of faction stability, this faction declines to accept new members for now. else { List members = new List(guild.Members); for (int i = 0; i < members.Count; ++i) { PlayerMobile member = members[i] as PlayerMobile; if (member == null) continue; this.JoinGuilded(member, guild); } } } else if (!this.CanHandleInflux(1)) { pm.SendLocalizedMessage(1018031); // In the interest of faction stability, this faction declines to accept new members for now. } else { this.JoinAlone(mob); } } public bool IsCommander(Mobile mob) { if (mob == null) return false; return (mob.AccessLevel >= AccessLevel.GameMaster || mob == this.Commander); } public Faction() { this.m_State = new FactionState(this); } public override string ToString() { return this.m_Definition.FriendlyName; } public int CompareTo(object obj) { return this.m_Definition.Sort - ((Faction)obj).m_Definition.Sort; } public static bool CheckLeaveTimer(Mobile mob) { PlayerState pl = PlayerState.Find(mob); if (pl == null || !pl.IsLeaving) return false; if ((pl.Leaving + LeavePeriod) >= DateTime.UtcNow) return false; mob.SendLocalizedMessage(1005163); // You have now quit your faction pl.Faction.RemoveMember(mob); return true; } public static void Initialize() { EventSink.Login += new LoginEventHandler(EventSink_Login); EventSink.Logout += new LogoutEventHandler(EventSink_Logout); Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(10.0), new TimerCallback(HandleAtrophy)); Timer.DelayCall(TimeSpan.FromSeconds(30.0), TimeSpan.FromSeconds(30.0), new TimerCallback(ProcessTick)); CommandSystem.Register("FactionElection", AccessLevel.GameMaster, new CommandEventHandler(FactionElection_OnCommand)); CommandSystem.Register("FactionCommander", AccessLevel.Administrator, new CommandEventHandler(FactionCommander_OnCommand)); CommandSystem.Register("FactionItemReset", AccessLevel.Administrator, new CommandEventHandler(FactionItemReset_OnCommand)); CommandSystem.Register("FactionReset", AccessLevel.Administrator, new CommandEventHandler(FactionReset_OnCommand)); CommandSystem.Register("FactionTownReset", AccessLevel.Administrator, new CommandEventHandler(FactionTownReset_OnCommand)); } public static void FactionTownReset_OnCommand(CommandEventArgs e) { List monoliths = BaseMonolith.Monoliths; for (int i = 0; i < monoliths.Count; ++i) monoliths[i].Sigil = null; List towns = Town.Towns; for (int i = 0; i < towns.Count; ++i) { towns[i].Silver = 0; towns[i].Sheriff = null; towns[i].Finance = null; towns[i].Tax = 0; towns[i].Owner = null; } List sigils = Sigil.Sigils; for (int i = 0; i < sigils.Count; ++i) { sigils[i].Corrupted = null; sigils[i].Corrupting = null; sigils[i].LastStolen = DateTime.MinValue; sigils[i].GraceStart = DateTime.MinValue; sigils[i].CorruptionStart = DateTime.MinValue; sigils[i].PurificationStart = DateTime.MinValue; sigils[i].LastMonolith = null; sigils[i].ReturnHome(); } List factions = Faction.Factions; for (int i = 0; i < factions.Count; ++i) { Faction f = factions[i]; List list = new List(f.State.FactionItems); for (int j = 0; j < list.Count; ++j) { FactionItem fi = list[j]; if (fi.Expiration == DateTime.MinValue) fi.Item.Delete(); else fi.Detach(); } } } public static void FactionReset_OnCommand(CommandEventArgs e) { List monoliths = BaseMonolith.Monoliths; for (int i = 0; i < monoliths.Count; ++i) monoliths[i].Sigil = null; List towns = Town.Towns; for (int i = 0; i < towns.Count; ++i) { towns[i].Silver = 0; towns[i].Sheriff = null; towns[i].Finance = null; towns[i].Tax = 0; towns[i].Owner = null; } List sigils = Sigil.Sigils; for (int i = 0; i < sigils.Count; ++i) { sigils[i].Corrupted = null; sigils[i].Corrupting = null; sigils[i].LastStolen = DateTime.MinValue; sigils[i].GraceStart = DateTime.MinValue; sigils[i].CorruptionStart = DateTime.MinValue; sigils[i].PurificationStart = DateTime.MinValue; sigils[i].LastMonolith = null; sigils[i].ReturnHome(); } List factions = Faction.Factions; for (int i = 0; i < factions.Count; ++i) { Faction f = factions[i]; List playerStateList = new List(f.Members); for (int j = 0; j < playerStateList.Count; ++j) f.RemoveMember(playerStateList[j].Mobile); List factionItemList = new List(f.State.FactionItems); for (int j = 0; j < factionItemList.Count; ++j) { FactionItem fi = (FactionItem)factionItemList[j]; if (fi.Expiration == DateTime.MinValue) fi.Item.Delete(); else fi.Detach(); } List factionTrapList = new List(f.Traps); for (int j = 0; j < factionTrapList.Count; ++j) factionTrapList[j].Delete(); } } public static void FactionItemReset_OnCommand(CommandEventArgs e) { ArrayList pots = new ArrayList(); foreach (Item item in World.Items.Values) { if (item is IFactionItem && !(item is HoodedShroudOfShadows)) pots.Add(item); } int[] hues = new int[Factions.Count * 2]; for (int i = 0; i < Factions.Count; ++i) { hues[0 + (i * 2)] = Factions[i].Definition.HuePrimary; hues[1 + (i * 2)] = Factions[i].Definition.HueSecondary; } int count = 0; for (int i = 0; i < pots.Count; ++i) { Item item = (Item)pots[i]; IFactionItem fci = (IFactionItem)item; if (fci.FactionItemState != null || item.LootType != LootType.Blessed) continue; bool isHued = false; for (int j = 0; j < hues.Length; ++j) { if (item.Hue == hues[j]) { isHued = true; break; } } if (isHued) { fci.FactionItemState = null; ++count; } } e.Mobile.SendMessage("{0} items reset", count); } public static void FactionCommander_OnCommand(CommandEventArgs e) { e.Mobile.SendMessage("Target a player to make them the faction commander."); e.Mobile.BeginTarget(-1, false, TargetFlags.None, new TargetCallback(FactionCommander_OnTarget)); } public static void FactionCommander_OnTarget(Mobile from, object obj) { if (obj is PlayerMobile) { Mobile targ = (Mobile)obj; PlayerState pl = PlayerState.Find(targ); if (pl != null) { pl.Faction.Commander = targ; from.SendMessage("You have appointed them as the faction commander."); } else { from.SendMessage("They are not in a faction."); } } else { from.SendMessage("That is not a player."); } } public static void FactionElection_OnCommand(CommandEventArgs e) { e.Mobile.SendMessage("Target a faction stone to open its election properties."); e.Mobile.BeginTarget(-1, false, TargetFlags.None, new TargetCallback(FactionElection_OnTarget)); } public static void FactionElection_OnTarget(Mobile from, object obj) { if (obj is FactionStone) { Faction faction = ((FactionStone)obj).Faction; if (faction != null) from.SendGump(new ElectionManagementGump(faction.Election)); //from.SendGump( new Gumps.PropertiesGump( from, faction.Election ) ); else from.SendMessage("That stone has no faction assigned."); } else { from.SendMessage("That is not a faction stone."); } } public static void FactionKick_OnCommand(CommandEventArgs e) { e.Mobile.SendMessage("Target a player to remove them from their faction."); e.Mobile.BeginTarget(-1, false, TargetFlags.None, new TargetCallback(FactionKick_OnTarget)); } public static void FactionKick_OnTarget(Mobile from, object obj) { if (obj is Mobile) { Mobile mob = (Mobile)obj; PlayerState pl = PlayerState.Find((Mobile)mob); if (pl != null) { pl.Faction.RemoveMember(mob); mob.SendMessage("You have been kicked from your faction."); from.SendMessage("They have been kicked from their faction."); } else { from.SendMessage("They are not in a faction."); } } else { from.SendMessage("That is not a player."); } } public static void ProcessTick() { List sigils = Sigil.Sigils; for (int i = 0; i < sigils.Count; ++i) { Sigil sigil = sigils[i]; if (!sigil.IsBeingCorrupted && sigil.GraceStart != DateTime.MinValue && (sigil.GraceStart + Sigil.CorruptionGrace) < DateTime.UtcNow) { if (sigil.LastMonolith is StrongholdMonolith && (sigil.Corrupted == null || sigil.LastMonolith.Faction != sigil.Corrupted)) { sigil.Corrupting = sigil.LastMonolith.Faction; sigil.CorruptionStart = DateTime.UtcNow; } else { sigil.Corrupting = null; sigil.CorruptionStart = DateTime.MinValue; } sigil.GraceStart = DateTime.MinValue; } if (sigil.LastMonolith == null || sigil.LastMonolith.Sigil == null) { if ((sigil.LastStolen + Sigil.ReturnPeriod) < DateTime.UtcNow) sigil.ReturnHome(); } else { if (sigil.IsBeingCorrupted && (sigil.CorruptionStart + Sigil.CorruptionPeriod) < DateTime.UtcNow) { sigil.Corrupted = sigil.Corrupting; sigil.Corrupting = null; sigil.CorruptionStart = DateTime.MinValue; sigil.GraceStart = DateTime.MinValue; } else if (sigil.IsPurifying && (sigil.PurificationStart + Sigil.PurificationPeriod) < DateTime.UtcNow) { sigil.PurificationStart = DateTime.MinValue; sigil.Corrupted = null; sigil.Corrupting = null; sigil.CorruptionStart = DateTime.MinValue; sigil.GraceStart = DateTime.MinValue; } } } } public static void HandleDeath(Mobile mob) { HandleDeath(mob, null); } #region Skill Loss public const double SkillLossFactor = 1.0 / 3; public static TimeSpan SkillLossPeriod { get { return Core.SA ? TimeSpan.FromMinutes(5) : TimeSpan.FromMinutes(20.0); } } private static readonly Dictionary m_SkillLoss = new Dictionary(); private class SkillLossContext { public Timer m_Timer; public List m_Mods; } public static bool InSkillLoss(Mobile mob) { return m_SkillLoss.ContainsKey(mob); } public static void ApplySkillLoss(Mobile mob) { if (InSkillLoss(mob)) return; SkillLossContext context = new SkillLossContext(); m_SkillLoss[mob] = context; List mods = context.m_Mods = new List(); for (int i = 0; i < mob.Skills.Length; ++i) { Skill sk = mob.Skills[i]; double baseValue = sk.Base; if (baseValue > 0) { SkillMod mod = new DefaultSkillMod(sk.SkillName, true, -(baseValue * SkillLossFactor)); mods.Add(mod); mob.AddSkillMod(mod); } } context.m_Timer = Timer.DelayCall(SkillLossPeriod, new TimerStateCallback(ClearSkillLoss_Callback), mob); } private static void ClearSkillLoss_Callback(object state) { ClearSkillLoss((Mobile)state); } public static bool ClearSkillLoss(Mobile mob) { SkillLossContext context; if (!m_SkillLoss.TryGetValue(mob, out context)) return false; m_SkillLoss.Remove(mob); List mods = context.m_Mods; for (int i = 0; i < mods.Count; ++i) mob.RemoveSkillMod(mods[i]); context.m_Timer.Stop(); return true; } #endregion public int AwardSilver(Mobile mob, int silver) { if (silver <= 0) return 0; int tithed = (silver * this.Tithe) / 100; this.Silver += tithed; silver = silver - tithed; if (silver > 0) mob.AddToBackpack(new Silver(silver)); return silver; } public virtual int MaximumTraps { get { return 15; } } public List Traps { get { return this.m_State.Traps; } set { this.m_State.Traps = value; } } public const int StabilityFactor = 300; // 300% greater (3 times) than smallest faction public const int StabilityActivation = 200; // Stablity code goes into effect when largest faction has > 200 people public static Faction FindSmallestFaction() { List factions = Factions; Faction smallest = null; for (int i = 0; i < factions.Count; ++i) { Faction faction = factions[i]; if (smallest == null || faction.Members.Count < smallest.Members.Count) smallest = faction; } return smallest; } public static bool StabilityActive() { List factions = Factions; for (int i = 0; i < factions.Count; ++i) { Faction faction = factions[i]; if (faction.Members.Count > StabilityActivation) return true; } return false; } public bool CanHandleInflux(int influx) { if (!StabilityActive()) return true; Faction smallest = FindSmallestFaction(); if (smallest == null) return true; // sanity if (StabilityFactor > 0 && (((this.Members.Count + influx) * 100) / StabilityFactor) > smallest.Members.Count) return false; return true; } public static void HandleDeath(Mobile victim, Mobile killer) { if (killer == null) killer = victim.FindMostRecentDamager(true); PlayerState killerState = PlayerState.Find(killer); Container pack = victim.Backpack; if (pack != null) { Container killerPack = (killer == null ? null : killer.Backpack); Item[] sigils = pack.FindItemsByType(typeof(Sigil)); for (int i = 0; i < sigils.Length; ++i) { Sigil sigil = (Sigil)sigils[i]; if (killerState != null && killerPack != null) { if (killer.GetDistanceToSqrt(victim) > 64) { sigil.ReturnHome(); killer.SendLocalizedMessage(1042230); // The sigil has gone back to its home location. } else if (Sigil.ExistsOn(killer)) { sigil.ReturnHome(); killer.SendLocalizedMessage(1010258); // The sigil has gone back to its home location because you already have a sigil. } else if (!killerPack.TryDropItem(killer, sigil, false)) { sigil.ReturnHome(); killer.SendLocalizedMessage(1010259); // The sigil has gone home because your backpack is full. } } else { sigil.ReturnHome(); } } } if (killerState == null) return; if (victim is BaseCreature) { BaseCreature bc = (BaseCreature)victim; Faction victimFaction = bc.FactionAllegiance; if (bc.Map == Faction.Facet && victimFaction != null && killerState.Faction != victimFaction) { int silver = killerState.Faction.AwardSilver(killer, 30); if (silver > 0) killer.SendLocalizedMessage(1042748, silver.ToString("N0")); // Thou hast earned ~1_AMOUNT~ silver for vanquishing the vile creature. } #region Ethics if (bc.Map == Faction.Facet && bc.GetEthicAllegiance(killer) == BaseCreature.Allegiance.Enemy) { Ethics.Player killerEPL = Ethics.Player.Find(killer); if (killerEPL != null && (100 - killerEPL.Power) > Utility.Random(100)) { ++killerEPL.Power; ++killerEPL.History; } } #endregion return; } PlayerState victimState = PlayerState.Find(victim); if (victimState == null) return; if (killer == victim || killerState.Faction != victimState.Faction) ApplySkillLoss(victim); if (killerState.Faction != victimState.Faction) { if (victimState.KillPoints <= -6) { killer.SendLocalizedMessage(501693); // This victim is not worth enough to get kill points from. #region Ethics Ethics.Player killerEPL = Ethics.Player.Find(killer); Ethics.Player victimEPL = Ethics.Player.Find(victim); if (killerEPL != null && victimEPL != null && victimEPL.Power > 0 && victimState.CanGiveSilverTo(killer)) { int powerTransfer = Math.Max(1, victimEPL.Power / 5); if (powerTransfer > (100 - killerEPL.Power)) powerTransfer = 100 - killerEPL.Power; if (powerTransfer > 0) { victimEPL.Power -= (powerTransfer + 1) / 2; killerEPL.Power += powerTransfer; killerEPL.History += powerTransfer; victimState.OnGivenSilverTo(killer); } } #endregion } else { int award = Math.Max(victimState.KillPoints / 10, 1); if (award > 40) award = 40; if (victimState.CanGiveSilverTo(killer)) { if (victimState.KillPoints > 0) { victimState.IsActive = true; if (1 > Utility.Random(3)) killerState.IsActive = true; int silver = 0; silver = killerState.Faction.AwardSilver(killer, award * 40); if (silver > 0) killer.SendLocalizedMessage(1042736, String.Format("{0:N0} silver\t{1}", silver, victim.Name)); // You have earned ~1_SILVER_AMOUNT~ pieces for vanquishing ~2_PLAYER_NAME~! } victimState.KillPoints -= award; killerState.KillPoints += award; int offset = (award != 1 ? 0 : 2); // for pluralization string args = String.Format("{0}\t{1}\t{2}", award, victim.Name, killer.Name); killer.SendLocalizedMessage(1042737 + offset, args); // Thou hast been honored with ~1_KILL_POINTS~ kill point(s) for vanquishing ~2_DEAD_PLAYER~! victim.SendLocalizedMessage(1042738 + offset, args); // Thou has lost ~1_KILL_POINTS~ kill point(s) to ~3_ATTACKER_NAME~ for being vanquished! #region Ethics Ethics.Player killerEPL = Ethics.Player.Find(killer); Ethics.Player victimEPL = Ethics.Player.Find(victim); if (killerEPL != null && victimEPL != null && victimEPL.Power > 0) { int powerTransfer = Math.Max(1, victimEPL.Power / 5); if (powerTransfer > (100 - killerEPL.Power)) powerTransfer = 100 - killerEPL.Power; if (powerTransfer > 0) { victimEPL.Power -= (powerTransfer + 1) / 2; killerEPL.Power += powerTransfer; killerEPL.History += powerTransfer; } } #endregion victimState.OnGivenSilverTo(killer); } else { killer.SendLocalizedMessage(1042231); // You have recently defeated this enemy and thus their death brings you no honor. } } } } private static void EventSink_Logout(LogoutEventArgs e) { Mobile mob = e.Mobile; Container pack = mob.Backpack; if (pack == null) return; Item[] sigils = pack.FindItemsByType(typeof(Sigil)); for (int i = 0; i < sigils.Length; ++i) ((Sigil)sigils[i]).ReturnHome(); } private static void EventSink_Login(LoginEventArgs e) { Mobile mob = e.Mobile; CheckLeaveTimer(mob); } public static readonly Map Facet = Map.Felucca; public static void WriteReference(GenericWriter writer, Faction fact) { int idx = Factions.IndexOf(fact); writer.WriteEncodedInt((int)(idx + 1)); } public static List Factions { get { return Reflector.Factions; } } public static Faction ReadReference(GenericReader reader) { int idx = reader.ReadEncodedInt() - 1; if (idx >= 0 && idx < Factions.Count) return Factions[idx]; return null; } public static Faction Find(Mobile mob) { return Find(mob, false, false); } public static Faction Find(Mobile mob, bool inherit) { return Find(mob, inherit, false); } public static Faction Find(Mobile mob, bool inherit, bool creatureAllegiances) { PlayerState pl = PlayerState.Find(mob); if (pl != null) return pl.Faction; if (inherit && mob is BaseCreature) { BaseCreature bc = (BaseCreature)mob; if (bc.Controlled) return Find(bc.ControlMaster, false); else if (bc.Summoned) return Find(bc.SummonMaster, false); else if (creatureAllegiances && mob is BaseFactionGuard) return ((BaseFactionGuard)mob).Faction; else if (creatureAllegiances) return bc.FactionAllegiance; } return null; } public static Faction Parse(string name) { List factions = Factions; for (int i = 0; i < factions.Count; ++i) { Faction faction = factions[i]; if (Insensitive.Equals(faction.Definition.FriendlyName, name)) return faction; } return null; } } public enum FactionKickType { Kick, Ban, Unban } public class FactionKickCommand : BaseCommand { private readonly FactionKickType m_KickType; public FactionKickCommand(FactionKickType kickType) { this.m_KickType = kickType; this.AccessLevel = AccessLevel.GameMaster; this.Supports = CommandSupport.AllMobiles; this.ObjectTypes = ObjectTypes.Mobiles; switch ( this.m_KickType ) { case FactionKickType.Kick: { this.Commands = new string[] { "FactionKick" }; this.Usage = "FactionKick"; this.Description = "Kicks the targeted player out of his current faction. This does not prevent them from rejoining."; break; } case FactionKickType.Ban: { this.Commands = new string[] { "FactionBan" }; this.Usage = "FactionBan"; this.Description = "Bans the account of a targeted player from joining factions. All players on the account are removed from their current faction, if any."; break; } case FactionKickType.Unban: { this.Commands = new string[] { "FactionUnban" }; this.Usage = "FactionUnban"; this.Description = "Unbans the account of a targeted player from joining factions."; break; } } } public override void Execute(CommandEventArgs e, object obj) { Mobile mob = (Mobile)obj; switch ( this.m_KickType ) { case FactionKickType.Kick: { PlayerState pl = PlayerState.Find(mob); if (pl != null) { pl.Faction.RemoveMember(mob); mob.SendMessage("You have been kicked from your faction."); this.AddResponse("They have been kicked from their faction."); } else { this.LogFailure("They are not in a faction."); } break; } case FactionKickType.Ban: { Account acct = mob.Account as Account; if (acct != null) { if (acct.GetTag("FactionBanned") == null) { acct.SetTag("FactionBanned", "true"); this.AddResponse("The account has been banned from joining factions."); } else { this.AddResponse("The account is already banned from joining factions."); } for (int i = 0; i < acct.Length; ++i) { mob = acct[i]; if (mob != null) { PlayerState pl = PlayerState.Find(mob); if (pl != null) { pl.Faction.RemoveMember(mob); mob.SendMessage("You have been banned from factions."); this.AddResponse("They have been banned from factions."); } } } } else { this.LogFailure("They have no assigned account."); } break; } case FactionKickType.Unban: { Account acct = mob.Account as Account; if (acct != null) { if (acct.GetTag("FactionBanned") == null) { this.AddResponse("The account is not already banned from joining factions."); } else { acct.RemoveTag("FactionBanned"); this.AddResponse("The account may now freely join factions."); } } else { this.LogFailure("They have no assigned account."); } break; } } } } }