/// <summary> /// Spawns a new power vortex at the _vortexSpawnLocation /// Starts the vortex expire timer. /// </summary> public void SpawnVortex() { //switch off scheduled mode.. m_ScheduledMode = false; //clear points from last time just in case m_DefensePoints.Clear(); m_Vortex = new PowerVortex(this); m_Vortex.MoveToWorld(m_VortexSpawnLocation, this.Map); //Start vortex expire timer m_Timer = new VortexExpireTimer(TimeSpan.FromMinutes(KinSystemSettings.VortexExpireMinutes), this); m_Timer.Start(); //Set the time variable to the end time so we can preserve on server restart m_Time = DateTime.Now + TimeSpan.FromMinutes(KinSystemSettings.VortexExpireMinutes); //Announce! KinSystem.SendKinMessage(string.Format("A power vortex targeting the City of {0} has appeared!", m_City.ToString())); }
/// <summary> /// Sets the type of the guard. /// </summary> /// <param name="type">The type.</param> private void SetGuardType(KinFactionGuardTypes type) { //Check if the new type is the same cost as the old type KinFactionGuardTypes currentType = (KinFactionGuardTypes)m_State.GetValue <KinFactionGuardTypes>("Type"); int cost = KinSystem.GetGuardCostType(type); int currentCost = KinSystem.GetGuardCostType(currentType); if (!cost.Equals(currentCost)) { //Modify the slots accordingly int slots = (int)m_State.GetValue <int>("Slots"); slots += (currentCost - cost); if (slots < 0) { return; } m_State.SetValue("Slots", slots); } m_State.SetValue("Type", type); }
/// <summary> /// Gets the guard text colour. /// </summary> /// <param name="guardType">Type of the guard.</param> /// <returns></returns> private int GetGuardTextColour(KinFactionGuardTypes guardType) { //less than five maint costs is low health int cost = KinSystem.GetGuardCostType(guardType); if (cost == (int)KinFactionGuardCostTypes.HighCost) { return(136); //red } //less than 10 maint costs is medium health if (cost == (int)KinFactionGuardCostTypes.MediumCost) { return(1359); //orange } if (cost == (int)KinFactionGuardCostTypes.LowCost) { return(271); //green! } return(130); //red TODO: Special colour here. }
public DailyCitySummary(KinCityData data) { if (data == null) { return; } LogTime = DateTime.Now; Kin = data.ControlingKin.ToString(); City = data.City.ToString(); if (data.CityLeader != null) { Leader = new Player(data.CityLeader as PlayerMobile); } data.BeneficiaryDataList.ForEach(delegate(KinCityData.BeneficiaryData bd) { if (bd.Pm != null) { Beneficiaries.Add(new Player(bd.Pm)); } }); Treasury = data.Treasury; TaxRate = data.TaxRate; NPCFlags = data.NPCCurrentFlags; GuardOption = (int)data.GuardOption; GuardPostSlots = string.Format("{0} | {1}", KinSystem.GetCityGuardPostSlots(data.City), data.UnassignedGuardPostSlots); foreach (KinCityData.BeneficiaryData bd in data.BeneficiaryDataList) { foreach (Items.KinGuardPost gp in bd.GuardPosts) { if (gp != null && !gp.Deleted) { GuardPostData.Add(new GuardPost(gp)); } } } }
public override void OnEnter(Mobile m) { Region left = null; PlayerMobile pm = null; if (m is PlayerMobile) { pm = (PlayerMobile)m; left = pm.LastRegionIn; } // wea: If this is an isolated region, we're going to send sparklies where // mobiles will disappear (this happens as part of an IsIsolatedFrom() check, // not explicit packet removal here) + a sound effect if we had to do this // // also send an incoming packet to all players within the region. // ____ // || if (m_Controller.IsIsolated) { if (m.Map != null) { int invissedmobiles = 0; IPooledEnumerable eable = m.GetMobilesInRange(Core.GlobalMaxUpdateRange); foreach (Mobile mir in eable) { // Regardless of whether this is mobile or playermobile, // we need to send an incoming packet to each of the mobiles // in the region if (mir.Region == m.Region) { if (mir is PlayerMobile) { // We've just walked into this mobile's region, so send incoming packet // if they're a playermobile if (Utility.InUpdateRange(m.Location, mir.Location) && mir.CanSee(m)) { // Send incoming packet to player if they're online if (mir.NetState != null) { mir.NetState.Send(new MobileIncoming(mir, m)); } } } } else { // They're in a different region, so localise sparklies // to us if we're a player mobile if (pm != null && mir.AccessLevel <= pm.AccessLevel) { Packet particles = new LocationParticleEffect(EffectItem.Create(mir.Location, mir.Map, EffectItem.DefaultDuration), 0x376A, 10, 10, 0, 0, 2023, 0); if (pm.NetState != null && particles != null) { pm.Send(particles); invissedmobiles++; } } } } if (invissedmobiles > 0) { // Play a sound effect to go with it if (pm.NetState != null) { pm.PlaySound(0x3C4); } } if (pm != null) { m.ClearScreen(); m.SendEverything(); } eable.Free(); } } // || // ____ // if were leaving a house and entering the region(already in it) dont play the enter msg if (pm != null && pm.LastRegionIn is HouseRegion) { return; } if (m_Controller.ShowEnterMessage) { m.SendMessage("You have entered {0}", this.Name); if (m_Controller.NoMurderZone) { m.SendMessage("This is a lawless area; you are freely attackable here."); } } if (m_Controller.OverrideMaxFollowers) { m.FollowersMax = m_Controller.MaxFollowerSlots; } if (m_Controller.PlayMusic) { PlayMusic(m); } PlayerMobile IOBenemy = null; if (m is PlayerMobile) { IOBenemy = (PlayerMobile)m; } //if is a iob zone/region and a iob aligned mobile with a differnt alignment then the zone enters //find all players of the zones alignment and send them a message //plasma: refactored the send message code into its own method within KinSystem if (DateTime.Now >= m_Controller.m_Msg && m_Controller.IOBZone && m_Controller.ShowIOBMsg && IOBenemy != null && IOBenemy.IOBAlignment != IOBAlignment.None && IOBenemy.IOBAlignment != m_Controller.IOBAlign && m.AccessLevel == AccessLevel.Player) //we dont want it announceing staff with iob kinship { if (m_Controller.RegionName != null && m_Controller.RegionName.Length > 0) { KinSystem.SendKinMessage(m_Controller.IOBAlign, string.Format("Come quickly, the {0} are attacking {1}!", IOBSystem.GetIOBName(IOBenemy.IOBRealAlignment), m_Controller.RegionName)); } else { KinSystem.SendKinMessage(m_Controller.IOBAlign, string.Format("Come quickly, the {0} are attacking your stronghold!", IOBSystem.GetIOBName(IOBenemy.IOBRealAlignment))); } m_Controller.m_Msg = DateTime.Now + m_Controller.m_Delay; } else if (DateTime.Now >= m_Controller.m_Msg && this is Engines.IOBSystem.KinCityRegion && IOBenemy != null && IOBenemy.IOBAlignment != IOBAlignment.None && IOBenemy.IOBAlignment != m_Controller.IOBAlign && m.AccessLevel == AccessLevel.Player) //we dont want it announceing staff with iob kinship { KinCityRegion r = KinCityRegion.GetKinCityAt(this.m_Controller); if (r != null) { KinCityData cd = KinCityManager.GetCityData(r.KCStone.City); if (cd != null && cd.ControlingKin != IOBAlignment.None) { Engines.IOBSystem.KinSystem.SendKinMessage(cd.ControlingKin, string.Format("Come quickly, the {0} are attacking the City of {1}!", IOBSystem.GetIOBName(IOBenemy.IOBRealAlignment), cd.City.ToString())); m_Controller.m_Msg = DateTime.Now + m_Controller.m_Delay; } } } base.OnEnter(m); }
/// <summary> /// Creation of the entity's graphics /// </summary> void ICommitGumpEntity.Create() { //Note: The first time the state is created it also takes a snapshot of the current slot distribution //This is to prevent exploits when commiting if (m_State == null) { m_State = new GumpState(m_Gump.Data); } #region page 4 // Page 4 - delegation ////////////////////////////////////////////////////////////////////// StringBuilder htmlSb = new StringBuilder("<basefont color=#FFCC00><center>Guard Post Delegation</center></basefont>"); m_Gump.AddHtml(170, 40, 409, 19, htmlSb.ToString(), (bool)false, (bool)false); //left htmlSb = new StringBuilder("<basefont color=gray><center>Here you may delegate the creation of guard posts to beneficiaries</center></basefont>"); m_Gump.AddHtml(170, 70, 409, 19, htmlSb.ToString(), (bool)false, (bool)false); //left htmlSb = new StringBuilder(string.Format("<basefont color=white><center>Guard Slots Remaining : {0}/{1}</center></basefont>", m_State.RemainingSlots, KinSystem.GetCityGuardPostSlots(m_Gump.City))); m_Gump.AddHtml(170, 100, 409, 19, htmlSb.ToString(), (bool)false, (bool)false); //left //Add a button and label for each beneficiary int buttonID = 1; int yLocation = 137; int ySpacing = 25; foreach (KinCityData.BeneficiaryData data in m_Gump.Data.BeneficiaryDataList) { int pageDivider = (buttonID / 22); int xLocation = 174 + (pageDivider * 230); m_Gump.AddButton(xLocation, yLocation, 2223, 2223, buttonID, GumpButtonType.Reply, 0); m_Gump.AddButton(xLocation + 20, yLocation, 2224, 2224, buttonID + 1, GumpButtonType.Reply, 0); string caption = string.Format("{0}/{1} slots : {2}", m_State.SlotsRemainingChanged[data.Pm] + m_State.SlotsAssigned[data.Pm], m_State.SlotsRemainingChanged[data.Pm], (data.Pm.Name.Length > 12 ? data.Pm.Name.Substring(0, 12) : data.Pm.Name)); m_Gump.AddLabel(xLocation + 45, yLocation - 5, GetStatusColour(data.Pm), caption); yLocation += ySpacing; if (buttonID == 21) { yLocation = 137; } buttonID += 2; } if (!((ICommitGumpEntity)this).Validate()) { m_Gump.AddHtml(169, 415, 412, 136, "<basefont color=red><center>Your City's guard data has been modified from elsewhere. You must close and start again.</center></basefont>", (bool)false, (bool)false); } else if (!ReferenceEquals(m_Gump.Data.CityLeader, m_Gump.From)) { m_Gump.AddHtml(169, 425, 412, 136, string.Format("<basefont color=gray><center>{0}</center></basefont>", "Only the city leader may make changes"), false, false); } else if (m_State.IsDirty) { m_Gump.AddHtml(169, 425, 412, 136, "<basefont color=gray><center>You must press OK before these changes will take effect</center></basefont>", false, false); } ////////////////////////////////////////////////////////////////////////////////////////////// m_State.Status = string.Empty; #endregion }
void ICommitGumpEntity.Create() { if (GuardPost.Owner == null) { return; } m_Gump.AddPage(0); m_Gump.AddImage(486, 28, 2623); m_Gump.AddImage(36, 1, 10861); m_Gump.AddImage(6, 33, 2623); m_Gump.AddImage(6, 242, 2623); m_Gump.AddImage(6, 15, 2620); m_Gump.AddImage(219, 14, 2621); m_Gump.AddImage(140, 33, 2623); m_Gump.AddImage(139, 242, 2623); m_Gump.AddImage(6, 452, 2626); m_Gump.AddImage(213, 462, 2621); m_Gump.AddImage(469, 451, 2628); m_Gump.AddImage(470, 14, 2622); m_Gump.AddImage(486, 41, 2623); m_Gump.AddImage(485, 243, 2623); m_Gump.AddImage(26, 14, 2621); m_Gump.AddImage(23, 462, 2621); m_Gump.AddAlphaRegion(493, 14, 22, 463); m_Gump.AddBackground(16, 25, 470, 440, 9270); m_Gump.AddAlphaRegion(8, 473, 499, 8); m_Gump.AddButton(401, 417, 247, 248, (int)Buttons.btnMenuMainOK, GumpButtonType.Reply, 0); m_Gump.AddHtml(45, 46, 412, 19, @"<basefont color=#FFCC00><center>Guard Post Customisation</basefont></center>", (bool)false, (bool)false); m_Gump.AddHtml(60, 76, 205, 314, "<basefont color=white><center>Guard Type</center></basefont>", (bool)false, (bool)false); m_Gump.AddHtml(286, 76, 199, 314, "<basefont color=white><center>Hire Rate</center></basefont>", (bool)false, (bool)false); //For the guards we could just use the enum directly but in this case i want to sort the guards by their cost type first. //And also possibly exclude guard types from this particular Kin. m_Types = KinSystem.GetEligibleGuardTypes(GuardPost.Owner.IOBRealAlignment); m_Types.Sort(delegate(KinFactionGuardTypes x, KinFactionGuardTypes y) //Sort by cost type so they are grouped { int costA = (int)KinSystem.GetGuardCostType(x); int costB = (int)KinSystem.GetGuardCostType(y); if (costA < costB) { return(1); } else if (costA == costB) { return(0); } else { return(-1); } } ); List <string> guardTypeStrings = new List <string>(); foreach (KinFactionGuardTypes t in m_Types) { guardTypeStrings.Add(KinSystem.GetEnumTypeDescription <KinFactionGuardTypes>(t)); } //Add complete button set of possible guards, in two columns. Hook response methods up. m_GuardTypeButtons = new ButtonSet ( m_Gump, guardTypeStrings, 2, 135, 25, 1153, 1150, 41, 115, 1000, //Anon methods GO! delegate(int id) { return(m_State.GetValue <KinFactionGuardTypes>("Type").Equals(m_Types[id])); }, //Get Status delegate(int id) { SetGuardType(m_Types[id]); }, //Click delegate(int id) { return(GetGuardTextColour(m_Types[id])); } //Get label colour ); m_Gump.AddHtml(75, 310, 230, 314, string.Format(m_MAINT, GetNextMaintTimeMinutes()), (bool)false, (bool)false); m_Gump.AddHtml(75, 335, 230, 314, string.Format(m_SLOTS, GetSlotTextColour(), m_State.GetValue <int>("Slots")), (bool)false, (bool)false); m_Gump.AddHtml(75, 360, 230, 314, string.Format(m_SILVER, GetSilverTextColour(), GuardPost.Silver), (bool)false, (bool)false); //Defrag creatures and show next hire time if there is no guard currently spawned. GuardPost.Defrag(); if (GuardPost.Creatures.Count == 0) { m_Gump.AddHtml(75, 385, 230, 314, string.Format(m_HIRE, GetNextHireTimeMinutes()), (bool)false, (bool)false); } //Add button set for the FightMode subset we are interested in. m_SpeedButtons = new ButtonSet ( m_Gump, typeof(KinGuardPost.HireSpeeds), 1, 0, 25, 1153, 1150, 340, 115, 2000, //Anon methods GO! delegate(int id) { return(((int)m_State.GetValue <KinGuardPost.HireSpeeds>("Speed")).Equals(id)); }, delegate(int id) { m_State.SetValue("Speed", (KinGuardPost.HireSpeeds)id); }, delegate(int id) { return(1359); } ); m_Gump.AddHtml(286, 200, 199, 314, "<basefont color=white><center>Target Priority</center></basefont>", (bool)false, (bool)false); //Add button set for the FightMode subset we are interested in. m_TargetButtons = new ButtonSet ( m_Gump, typeof(FightModeButtons), 1, 0, 25, 1153, 1150, 340, 230, 3000, //note: these are flags so we give them the highest offset //Anon methods GO! delegate(int id) { return((((int)m_State.GetValue <FightMode>("Target")) & id) != 0); }, delegate(int id) { SetTarget((FightMode)id); }, delegate(int id) { return(1359); } ); /* * m_Gump.AddHtml(286, 310, 199, 314, "<basefont color=white><center>Fight Style</center></basefont>", (bool)false, (bool)false); * * spacer = 315; * * m_Gump.AddLabel(380, spacer += 25, 1359, @"Melee"); * m_Gump.AddButton(340, spacer, 1150, 1153, (int)Buttons.btnStyleMelee, GumpButtonType.Reply, 0); * m_Gump.AddLabel(380, spacer += 25, 1359, @"Magic"); * m_Gump.AddButton(340, spacer, 1150, 1153, (int)Buttons.btnStyleMagic, GumpButtonType.Reply, 0); */ if (m_State.IsValueDirty <KinFactionGuardTypes>("Type") || m_State.IsValueDirty <int>("Slots") || m_State.IsValueDirty <KinGuardPost.HireSpeeds>("Speed") || m_State.IsValueDirty <FightMode>("Target")) { m_Gump.AddHtml(10, 415, 412, 136, m_OK, (bool)false, (bool)false); } }
/// <summary> /// Commit any outstanding changes /// </summary> /// <param name="sender"></param> void ICommitGumpEntity.CommitChanges() { if (!((ICommitGumpEntity)this).Validate()) { m_Gump.From.SendMessage("The guard post has been changed since you were modifying it. Please make the changes again."); return; } if (m_State.IsValueDirty <KinFactionGuardTypes>("Type")) { //set guard type //TODO: - check some delay? GuardPost.GuardType = (KinFactionGuardTypes)m_State.GetValue <KinFactionGuardTypes>("Type"); m_Gump.From.SendMessage("Guard type changed to {0}.", KinSystem.GetEnumTypeDescription <KinFactionGuardTypes>((KinFactionGuardTypes)m_State.GetValue <KinFactionGuardTypes>("Type"))); } if (m_State.IsValueDirty <KinGuardPost.HireSpeeds>("Speed")) { GuardPost.HireSpeed = (KinGuardPost.HireSpeeds)m_State.GetValue <KinGuardPost.HireSpeeds>("Speed"); m_Gump.From.SendMessage("Hire rate successfully changed to {0}", KinSystem.GetEnumTypeDescription <KinGuardPost.HireSpeeds>((KinGuardPost.HireSpeeds)m_State.GetValue <KinGuardPost.HireSpeeds>("Speed"))); GuardPost.RefreshNextSpawnTime(); } if (m_State.IsValueDirty <int>("Slots")) { KinFactionGuardTypes currentType = (KinFactionGuardTypes)m_State.GetOriginalValue <KinFactionGuardTypes>("Type"); KinFactionGuardTypes type = (KinFactionGuardTypes)m_State.GetValue <KinFactionGuardTypes>("Type"); int cost = KinSystem.GetGuardCostType(type); int currentCost = KinSystem.GetGuardCostType(currentType); int slots = 0; slots += (currentCost - cost); KinCityData data = KinCityManager.GetCityData(GuardPost.City); if (data == null) { return; } KinCityData.BeneficiaryData bd = data.GetBeneficiary(GuardPost.Owner); if (bd == null) { return; } bd.ModifyGuardSlots(slots); m_Gump.From.SendMessage("Unassigned guard slots modified by {0}.", slots); } /* * if (m_State.StyleChanged) * { * //Assign new style * GuardPost.FightStyle = m_State.Style; * } */ if (m_State.IsValueDirty <FightMode>("Target")) { //Dont overwrite this one // 0 the strongest, weakest, closest //NAND out the options so these bits are all 0 GuardPost.FightMode &= ~FightMode.Strongest; GuardPost.FightMode &= ~FightMode.Weakest; GuardPost.FightMode &= ~FightMode.Closest; //write new version GuardPost.FightMode |= (FightMode)m_State.GetValue <FightMode>("Target"); m_Gump.From.SendMessage("Guard target priority successfully changed."); GuardPost.UpdateExisitngGuards(); } }
/// <summary> /// Called when the vortex is sucessfully killed /// All the points calculation and processing happens here /// </summary> public void VortexDeath() { CaptureData logData = new CaptureData(); logData.City = m_City.ToString(); logData.CaptureTime = DateTime.Now; logData.LogTime = DateTime.Now; //turn off expire timer if (m_Timer != null && m_Timer.Running) { m_Timer.Stop(); } if (KinSystemSettings.OutputCaptureData) { SendMessageToLocalGM(string.Format("Vortex for the city of {0} has been destroyed", m_City.ToString())); } Dictionary <PlayerMobile, double> individualCapturePoints //dual purpose damage dictionary and capture points = new Dictionary <PlayerMobile, double>(); Dictionary <IOBAlignment, int> kinDamageSpread //kin damage spread dictionary = new Dictionary <IOBAlignment, int>(); KinCapturePointList kinCapturePoints = new KinCapturePointList(); //final kin capture point list KinCapturePointList finalCapturePoints = new KinCapturePointList(); //final individual capture point list IOBAlignment winningKin = IOBAlignment.None; //Winning kin double capturePointsPerVortexDamage = 0.0; //Standardised capture points per vortex damage point double capturePointsPerDefensePoint = 0.0; //Standardised capture points per defense point double totalCapturePoints = 0.0; //total capture points int totalVortexDamage = 0; //total vortex damage //First, cycle thru the vortex's damage list and populate individual and kin damage dictionaries foreach (DamageEntry de in m_Vortex.DamageEntries) { PlayerMobile pm = null; //Check this is a real factioner or a factioner's pet if (de.Damager is PlayerMobile && ((PlayerMobile)de.Damager).IsRealFactioner) { pm = ((PlayerMobile)de.Damager); } else if (de.Damager is BaseCreature) { BaseCreature bc = ((BaseCreature)de.Damager); if (bc.ControlMaster != null && bc.ControlMaster is PlayerMobile && ((PlayerMobile)bc.ControlMaster).IsRealFactioner) { pm = ((PlayerMobile)bc.ControlMaster); } else if (bc.Summoned && bc.SummonMaster != null && bc.SummonMaster is PlayerMobile && ((PlayerMobile)bc.SummonMaster).IsRealFactioner) { pm = ((PlayerMobile)bc.SummonMaster); } } if (pm == null) { continue; } //add this player and the damage to the dictionary, to be converted into capture points in the next stage if (individualCapturePoints.ContainsKey(pm)) { individualCapturePoints[pm] += de.DamageGiven; } else { individualCapturePoints.Add(pm, de.DamageGiven); } //keep running total of all damage totalVortexDamage += de.DamageGiven; //also add this damage to the kin dictionary for later if (!kinDamageSpread.ContainsKey(pm.IOBRealAlignment)) { kinDamageSpread.Add(pm.IOBRealAlignment, de.DamageGiven); } else { kinDamageSpread[pm.IOBRealAlignment] += de.DamageGiven; } } //add anyone else from the defense points into the damage list, with 0 damage foreach (PlayerMobile pm in m_DefensePoints.Keys) { if (!individualCapturePoints.ContainsKey(pm)) { individualCapturePoints.Add(pm, 0.0); } } //add up defense points, this will act as the total amount of capture points avaliable foreach (KeyValuePair <PlayerMobile, double> pair in m_DefensePoints) { totalCapturePoints += pair.Value; } //Make sure we have at least 1 capture point to work with if (totalCapturePoints == 0) { totalCapturePoints = 1; } //standardise each damage point of the vortex damage so the vortex is worth KinSystemSettings % of the points capturePointsPerVortexDamage = ((totalCapturePoints * KinSystemSettings.VortexCaptureProportion) / totalVortexDamage); //the remainder contributes to defenders capturePointsPerDefensePoint = ((totalCapturePoints * (1.0 - KinSystemSettings.VortexCaptureProportion) / totalCapturePoints)); //output data thus far to local GM's journal if (KinSystemSettings.OutputCaptureData) { //Individual damage SendMessageToLocalGM("Individual damage to vortex:"); foreach (KeyValuePair <PlayerMobile, double> kvp in individualCapturePoints) { Player p = new Player(kvp.Key); p.Value = kvp.Value; logData.IndividualVortexDamage.Add(p); SendMessageToLocalGM(string.Format("Player {0} inflicted {1} points of damage", kvp.Key.Name, kvp.Value)); } //Total damage SendMessageToLocalGM(string.Format("Total damage inflicted on vortex: {0}", totalVortexDamage)); logData.TotalVortexDamage = totalVortexDamage; //Damage split by Kin SendMessageToLocalGM("Kin damage to vortex:"); foreach (KeyValuePair <IOBAlignment, int> kvp in kinDamageSpread) { StringDoublePair k = new StringDoublePair(); k.Name = kvp.Key.ToString(); k.Value = kvp.Value; logData.KinDamageSpread.Add(k); SendMessageToLocalGM(string.Format("Kin {0} inflicted {1} points of damage", kvp.Key.ToString(), kvp.Value)); } //Individual defense points SendMessageToLocalGM("Individual defense points earnt:"); foreach (KeyValuePair <PlayerMobile, double> kvp in m_DefensePoints) { Player p = new Player(kvp.Key); p.Value = kvp.Value; logData.IndividualDefensePoints.Add(p); SendMessageToLocalGM(string.Format("Player {0} earnt {1} defense points", kvp.Key.Name, kvp.Value)); } //Total defense points SendMessageToLocalGM(string.Format("Total defense (capture) points earnt: {0}", totalCapturePoints)); logData.TotalCapturePoints = totalCapturePoints; //Calculated points SendMessageToLocalGM(string.Format("Capture points per vortex damage : {0}", capturePointsPerVortexDamage)); SendMessageToLocalGM(string.Format("Capture points per defense point : {0}", capturePointsPerDefensePoint)); } //Reformat the individual list into capture points. List <PlayerMobile> pms = new List <PlayerMobile>(); //Temp list foreach (PlayerMobile pm in individualCapturePoints.Keys) { pms.Add(pm); } foreach (PlayerMobile pm in pms) { //reformat damage points individualCapturePoints[pm] *= capturePointsPerVortexDamage; if (m_DefensePoints.ContainsKey(pm)) { //Add any more capture points from defense individualCapturePoints[pm] += (m_DefensePoints[pm] * capturePointsPerDefensePoint); } //add this player's total capture points towards kin total kinCapturePoints.AddPoints(pm.IOBRealAlignment, individualCapturePoints[pm]); } //Free up temp list! pms.Clear(); pms = null; //Sort kin capture points (desc) kinCapturePoints.Sort(); //More output data if (KinSystemSettings.OutputCaptureData) { SendMessageToLocalGM("Total individual capture points:"); foreach (KeyValuePair <PlayerMobile, double> kvp in individualCapturePoints) { Player p = new Player(kvp.Key); p.Value = kvp.Value; logData.IndividualCapturePoints.Add(p); SendMessageToLocalGM(string.Format("Player {0} earnt {1} total capture points", kvp.Key.Name, kvp.Value)); } SendMessageToLocalGM("Total kin capture points:"); foreach (KinCapturePoints points in kinCapturePoints) { StringDoublePair k = new StringDoublePair(); k.Name = points.Obj.ToString(); k.Value = points.Points; logData.KinCapturePoints.Add(k); SendMessageToLocalGM(string.Format("Kin {0} earnt {1} total capture points", points.Obj.ToString(), points.Points)); } } //Now find a winner - but the winning kin must also have done at least x% of the vortex damage for (int i = 0; i < kinCapturePoints.Count; ++i) { IOBAlignment kin = IOBAlignment.None; if (kinCapturePoints[i].Obj is IOBAlignment) { kin = (IOBAlignment)kinCapturePoints[i].Obj; } int damage = 0; if (kinDamageSpread.ContainsKey(kin)) { damage = kinDamageSpread[kin]; } else { damage = 0; } if (damage >= (totalVortexDamage * KinSystemSettings.VortexMinDamagePercentage)) { //found our winner winningKin = kin; break; } else { if (KinSystemSettings.OutputCaptureData) { SendMessageToLocalGM(string.Format("Kin {0} would have won, but didn't do enough damage to the vortex", kin.ToString())); } } } logData.WinningKin = winningKin.ToString(); if (winningKin == IOBAlignment.None || winningKin == IOBAlignment.Healer || winningKin == IOBAlignment.OutCast) { //this shouldn't really happen. //Hand city over to golem controllers KinCityManager.TransferOwnership(m_City, IOBAlignment.None, null); } //Find and move all of this kin into the final capture point list foreach (KeyValuePair <PlayerMobile, double> pair in individualCapturePoints) { if (pair.Key.IOBRealAlignment == winningKin) { finalCapturePoints.AddPoints(pair.Key, pair.Value); } } //woo sanity if (finalCapturePoints.Count == 0) { //this should never happen. //Hand city over to golem controllers KinCityManager.TransferOwnership(m_City, IOBAlignment.None, null); } //Sort capture points list desc finalCapturePoints.Sort(); int totalBenes = 0; //now we want the top x% of this list to act as beneficiaries for the town, with a cap if (finalCapturePoints.Count < KinSystemSettings.BeneficiaryCap) { totalBenes = finalCapturePoints.Count; } else { //plasma: removing the qualification % for now, it's too inhibitive with a little amount of players. totalBenes = KinSystemSettings.BeneficiaryCap; //totalBenes = (int)Math.Round((double)finalCapturePoints.Count * KinSystemSettings.BeneficiaryQualifyPercentage, 0); //Should never happen, but possible depending on the KinSystemSettings variables if (totalBenes < 1) { totalBenes = 1; } } //Send message to winners List <PlayerMobile> winners = new List <PlayerMobile>(); for (int i = 0; i < totalBenes; ++i) { winners.Add(finalCapturePoints[i].Obj as PlayerMobile); } //Send message to all KinSystem.SendKinMessage(string.Format("The City of {0} has fallen to the {1}! ", m_City.ToString(), winningKin == IOBAlignment.None ? "Golem Controller Lord" : IOBSystem.GetIOBName(winningKin))); winners.ForEach(delegate(PlayerMobile pm) { pm.SendMessage("You have qualified as a beneficiary of {0}. Head to the city's control board to vote for a City leader.", m_City.ToString()); }); if (KinSystemSettings.OutputCaptureData) { SendMessageToLocalGM("Final beneficiaries of town:"); foreach (PlayerMobile pm in winners) { Player p = new Player(pm); logData.BeneficiariesCpaturePoints.Add(p); SendMessageToLocalGM(pm.Name); } } //Hand city over to the kin and its beneficiaries KinCityManager.TransferOwnership(m_City, winningKin, winners); m_DefensePoints.Clear(); if (KinSystemSettings.OutputCaptureData) { KinFactionLogs.Instance.AddEntityToSerialize(logData); } //Fianlly set the base next vortex spawn time for this city/sigil SetNewSpawnTime(); }