Example #1
0
 /// <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()));
 }
Example #2
0
            /// <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);
            }
Example #3
0
            /// <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.
            }
Example #4
0
 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));
             }
         }
     }
 }
Example #5
0
        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);
        }
Example #6
0
            /// <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
            }
Example #7
0
            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);
                }
            }
Example #8
0
            /// <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();
                }
            }
Example #9
0
        /// <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();
        }