Esempio n. 1
0
        public void TestWaterRightsOwner()
        {
            TestHelpers.InMethod();

            BuyPoint bp1 = new BuyPoint(UUID.Zero);
            Player   p1  = new Player("PLAYER 1", UUID.Parse("00000000-0000-0000-0000-000000000001"));
            Player   p2  = new Player("PLAYER 2", UUID.Parse("00000000-0000-0000-0000-000000000002"));

            Assert.That(bp1.WaterRightsOwner, Is.EqualTo(Player.None));
            Assert.That(p1.WaterRightsOwned.Count, Is.EqualTo(0));

            bp1.WaterRightsOwner = p1;

            Assert.That(bp1.WaterRightsOwner, Is.EqualTo(p1));
            Assert.That(p1.WaterRightsOwned.Count, Is.EqualTo(1));
            Assert.That(p1.WaterRightsOwned[UUID.Zero], Is.EqualTo(bp1));

            bp1.WaterRightsOwner = p2;

            Assert.That(bp1.WaterRightsOwner, Is.EqualTo(p2));
            Assert.That(p1.WaterRightsOwned.Count, Is.EqualTo(0));
            Assert.That(p2.WaterRightsOwned.Count, Is.EqualTo(1));
            Assert.That(p2.WaterRightsOwned[UUID.Zero], Is.EqualTo(bp1));
        }
Esempio n. 2
0
 public void RemoveBuyPointView(BuyPoint bp)
 {
 }
Esempio n. 3
0
        protected AbstractGameAsset AddGameAsset(BuyPoint bp, int fieldNumber, AbstractGameAsset template, int level)
        {
            List <Field> fields = new List <Field>(bp.Fields.Values);

            return(m_controller.State.BuildGameAsset(fields[fieldNumber], template, level));
        }
Esempio n. 4
0
 protected void AddHouses(BuyPoint bp)
 {
     h1 = (Houses)AddGameAsset(bp, 0, Houses.Template, 1);
     h2 = (Houses)AddGameAsset(bp, 1, Houses.Template, 2);
     h3 = (Houses)AddGameAsset(bp, 2, Houses.Template, 3);
 }
Esempio n. 5
0
        public override void SellRights(BuyPoint bp, Player buyer, RightsType type, int salePrice)
        {
            Player seller = Player.None;

            if (type == RightsType.Development || type == RightsType.Combined)
            {
                seller = bp.DevelopmentRightsOwner;
            }
            else
            {
                seller = bp.WaterRightsOwner;
            }

            if (!bp.OwnerActions.ContainsKey("SellDevelopmentRights"))
            {
                throw new WaterWarsGameLogicException(
                          "Player {0} tried to sell development rights on {1} in {2} but they have already sold game assets to the economy on this parcel",
                          seller.Name, bp.Name, bp.Location.RegionName);
            }

            if (buyer.Money < salePrice)
            {
                throw new WaterWarsGameLogicException(
                          "Player {0} tried to buy {1} rights for {2} from {3} for {4} but they only have {5}",
                          buyer, type, bp, seller, salePrice, buyer.Money);
            }

            m_log.InfoFormat(
                "[WATER WARS]: Player {0} selling {1} rights of {2} to {3} for {4}",
                seller, type, bp, buyer, salePrice);

            // Perform the transaction
            if (type == RightsType.Water || type == RightsType.Combined)
            {
                bp.WaterRightsOwner = buyer;
            }

            buyer.Money                -= salePrice;
            buyer.LandCostsThisTurn    += salePrice;
            seller.Money               += salePrice;
            seller.LandRevenueThisTurn += salePrice;

            // If we're selling development rights then we also need to remove any game assets already on the parcel
            if (type == RightsType.Development || type == RightsType.Combined)
            {
                lock (bp.GameAssets)
                {
                    foreach (AbstractGameAsset asset in bp.GameAssets.Values)
                    {
                        m_controller.Dispatcher.RemoveGameAssetView(asset);
                    }
                }

                bp.RemoveAllGameAssets();
            }

            if (type == RightsType.Development || type == RightsType.Combined)
            {
                TransferDevelopmentRights(bp, buyer);
            }

            m_controller.EventManager.TriggerLandRightsSold(bp, buyer, seller, type, salePrice, true);
            buyer.TriggerChanged();
            seller.TriggerChanged();
            bp.TriggerChanged();

            // FIXME: Should be done via event subscription.
            UpdateHudStatus(buyer);
            UpdateHudStatus(seller);

            m_controller.Events.PostToAll(
                string.Format(SELL_RIGHTS_CRAWL_MSG, seller.Name, type, bp.Name, bp.Location.RegionName, buyer.Name),
                EventLevel.Crawl);
        }
Esempio n. 6
0
        public void TestMultiTiersUnderAllocation()
        {
            TestHelpers.InMethod();
            //log4net.Config.XmlConfigurator.Configure();

            int water = 2600;

            Player        p1      = new Player("Alfred", UUID.Parse("00000000-0000-0000-0000-000000000001"));
            Player        p2      = new Player("Betty", UUID.Parse("00000000-0000-0000-0000-000000000002"));
            List <Player> players = new List <Player> {
                p1, p2
            };

            BuyPoint bp1_1 = new BuyPoint(UUID.Parse("00000000-0000-0000-0000-000000000010"))
            {
                WaterRightsOwner = p1
            };

            bp1_1.Location.LocalPosition = new Vector3(10, 80, 10);
            BuyPoint bp1_2 = new BuyPoint(UUID.Parse("00000000-0000-0000-0000-000000000020"))
            {
                WaterRightsOwner = p2
            };

            bp1_2.Location.LocalPosition = new Vector3(30, 70, 20);

            BuyPoint bp2_1 = new BuyPoint(UUID.Parse("00000000-0000-0000-0000-000000000030"))
            {
                WaterRightsOwner = p1
            };

            bp2_1.Location.LocalPosition = new Vector3(05, 35, 20);
            BuyPoint bp2_2 = new BuyPoint(UUID.Parse("00000000-0000-0000-0000-000000000040"))
            {
                WaterRightsOwner = p2
            };

            bp2_2.Location.LocalPosition = new Vector3(10, 25, 20);
            BuyPoint bp2_3 = new BuyPoint(UUID.Parse("00000000-0000-0000-0000-000000000050"))
            {
                WaterRightsOwner = p1
            };

            bp2_3.Location.LocalPosition = new Vector3(30, 27, 20);

            List <BuyPoint> buyPoints = new List <BuyPoint> {
                bp1_1, bp1_2, bp2_1, bp2_2, bp2_3
            };

            Dictionary <Player, int> allocation = distributor.Allocate(water, players, buyPoints);

            int firstTierParcelsGet  = TestParcelWaterEntitlement;
            int secondTierParcelsGet = (water - TestParcelWaterEntitlement * 2) / 3;

            Assert.That(allocation[p1], Is.EqualTo(firstTierParcelsGet + secondTierParcelsGet * 2));
            Assert.That(allocation[p2], Is.EqualTo(firstTierParcelsGet + secondTierParcelsGet));

            Assert.That(bp1_1.WaterAvailable, Is.EqualTo(firstTierParcelsGet));
            Assert.That(bp1_2.WaterAvailable, Is.EqualTo(firstTierParcelsGet));

            Assert.That(bp2_1.WaterAvailable, Is.EqualTo(secondTierParcelsGet));
            Assert.That(bp2_2.WaterAvailable, Is.EqualTo(secondTierParcelsGet));
            Assert.That(bp2_3.WaterAvailable, Is.EqualTo(secondTierParcelsGet));
        }
Esempio n. 7
0
        public BuyPointView(WaterWarsController controller, Scene scene, AbstractView itemStoreView, BuyPoint bp)
            : base(controller, scene, itemStoreView)
        {
            m_bp           = bp;
            m_bp.OnChange += Update;

            m_veSceneObjectNames[AbstractGameAssetType.None]    = "For Sale";
            m_veSceneObjectNames[AbstractGameAssetType.Crops]   = "Farmhouse";
            m_veSceneObjectNames[AbstractGameAssetType.Houses]  = "Site Office";
            m_veSceneObjectNames[AbstractGameAssetType.Factory] = "Portacabin";
        }
Esempio n. 8
0
 public Field GetField(BuyPoint bp, string rawUuid)
 {
     return(GetField(bp, WaterWarsUtils.ParseRawId(rawUuid)));
 }
Esempio n. 9
0
 public virtual void RegisterBuyPoint(BuyPoint bp)
 {
     throw new NotImplementedException();
 }
Esempio n. 10
0
 public virtual void SellRights(BuyPoint bp, Player buyer, RightsType type, int salePrice)
 {
     throw new NotImplementedException();
 }
Esempio n. 11
0
 public virtual void BuyLandRights(BuyPoint bp, Player p)
 {
     throw new NotImplementedException();
 }
Esempio n. 12
0
 public virtual void ChangeBuyPointName(BuyPoint bp, string newName)
 {
     throw new NotImplementedException();
 }
Esempio n. 13
0
 public virtual void UpdateBuyPointStatus(BuyPoint bp)
 {
 }
Esempio n. 14
0
 /// <summary>
 /// Transfer water rights to a given player from a parcel.
 /// </summary>
 /// <param name="bp"></param>
 /// <param name="p"></param>
 protected void TransferWaterRights(BuyPoint bp, Player p)
 {
     bp.WaterRightsOwner = p;
     p.WaterEntitlement += bp.InitialWaterRights;
 }
Esempio n. 15
0
 protected void TransferAllRights(BuyPoint bp, Player p)
 {
     TransferDevelopmentRights(bp, p);
     TransferWaterRights(bp, p);
 }
        public AskLandBuyerInteraction(
            WaterWarsController controller, HudView playerHud, HudView targetPlayerHud, BuyPoint bp,
            int salePrice, RightsType rightsToSell)
            : base(controller, playerHud, targetPlayerHud)
        {
            m_bp = bp;
            if (!m_controller.Game.Players.TryGetValue(playerHud.UserId, out m_p))
            {
                return;
            }
            if (!m_controller.Game.Players.TryGetValue(targetPlayerHud.UserId, out m_targetPlayer))
            {
                return;
            }
            m_salePrice    = salePrice;
            m_rightsToSell = rightsToSell;

            AskBuyer();
        }
Esempio n. 17
0
 public AbstractGameAsset GetAsset(BuyPoint bp, string rawUuid)
 {
     return(GetAsset(bp, WaterWarsUtils.ParseRawId(rawUuid)));
 }
Esempio n. 18
0
 public void RemoveBuyPointView(BuyPoint bp)
 {
     lock (m_buyPointViews)
         GetBuyPointView(bp.Uuid).Close();
 }
Esempio n. 19
0
 public void Initialize(BuyPoint bp)
 {
     m_bp = bp;
 }
Esempio n. 20
0
        protected Hashtable HandleBuyRights(
            BuyPoint bp, bool buyingDevelopmentRights, bool buyingWaterRights,
            string rawDevelopmentRightsBuyerId, string rawWaterRightsBuyerId,
            int?developmentRightsPrice, int?waterRightsPrice, int?combinedRightsPrice, Hashtable request)
        {
            if (bp.DevelopmentRightsOwner == Player.None)
            {
                m_controller.Resolver.BuyLandRights(bp.Uuid.ToString(), rawDevelopmentRightsBuyerId);
            }
            else
            {
                UUID developmentRightsBuyerId = UUID.Zero;
                if (rawDevelopmentRightsBuyerId != null)
                {
                    developmentRightsBuyerId = WaterWarsUtils.ParseRawId(rawDevelopmentRightsBuyerId);
                }

                UUID waterRightsBuyerId = UUID.Zero;
                if (rawWaterRightsBuyerId != null)
                {
                    waterRightsBuyerId = WaterWarsUtils.ParseRawId(rawWaterRightsBuyerId);
                }

                // TODO: Do player ownership checks later when we have access to this via security

                if (buyingDevelopmentRights && buyingWaterRights)
                {
                    if (null == combinedRightsPrice)
                    {
                        throw new Exception(
                                  string.Format("No combined rights price specified for sale of {0} rights", bp));
                    }

                    m_controller.Resolver.SellRights(
                        bp, developmentRightsBuyerId, RightsType.Combined, (int)combinedRightsPrice);
                }
                else if (buyingDevelopmentRights)
                {
                    if (null == developmentRightsPrice)
                    {
                        throw new Exception(
                                  string.Format("No development rights price specified for sale of {0} rights", bp));
                    }

                    m_controller.Resolver.SellRights(
                        bp, developmentRightsBuyerId, RightsType.Development, (int)developmentRightsPrice);
                }
                else if (buyingWaterRights)
                {
                    if (null == waterRightsPrice)
                    {
                        throw new Exception(
                                  string.Format("No water rights price specified for sale of {0} rights", bp));
                    }

                    m_controller.Resolver.SellRights(
                        bp, waterRightsBuyerId, RightsType.Water, (int)waterRightsPrice);
                }
            }

            // TODO: Deal with error situations: uuid not valid, no such buy point, not enough money, etc.

            Hashtable reply = new Hashtable();

            reply["int_response_code"]   = 200; // 200 OK
            reply["str_response_string"] = "hoorah";
            reply["content_type"]        = "text/plain";

            return(reply);
        }
Esempio n. 21
0
 public override void ChangeBuyPointName(BuyPoint bp, string newName)
 {
     bp.Name = newName;
     bp.TriggerChanged();
 }
Esempio n. 22
0
 public static string SerializeBuyPoint(BuyPoint bp)
 {
     return(JsonConvert.SerializeObject(bp, Formatting.Indented));
 }
        public void Execute(GameStartingState state)
        {
            List <Player>   farmers      = state.Game.Players.Values.Where(p => p.Role.Type == RoleType.Farmer).ToList();
            List <BuyPoint> riverParcels = state.Game.BuyPoints.Values.Where(p => p.Zone == "river").ToList();

            m_log.InfoFormat(
                "[WATER WARS]: Found {0} farmers and {1} river parcels", farmers.Count, riverParcels.Count);

            if (farmers.Count == 0)
            {
                m_log.InfoFormat("[WATER WARS]: Not allocating any farms since there are no farmers");
                return;
            }

            riverParcels.Sort(
                delegate(BuyPoint bp1, BuyPoint bp2)
            {
                if (bp1.Location.RegionY > bp2.Location.RegionY)
                {
                    return(1);
                }
                else if (bp1.Location.RegionY < bp2.Location.RegionY)
                {
                    return(-1);
                }

                if (bp1.Location.LocalPosition.Y > bp2.Location.LocalPosition.Y)
                {
                    return(1);
                }
                else if (bp1.Location.LocalPosition.Y < bp2.Location.LocalPosition.Y)
                {
                    return(-1);
                }

                if (bp1.Location.RegionX < bp2.Location.RegionX)
                {
                    return(1);
                }
                else if (bp1.Location.RegionY > bp2.Location.RegionY)
                {
                    return(-1);
                }

                if (bp1.Location.LocalPosition.X < bp2.Location.LocalPosition.X)
                {
                    return(1);
                }
                else if (bp1.Location.LocalPosition.X > bp2.Location.LocalPosition.X)
                {
                    return(-1);
                }

                return(0);
            });
            riverParcels.Reverse();

            m_log.InfoFormat("[WATER WARS]: River parcels are in this order");
            string tableFormat = "{0,-20}  {1,-30}  {2,-6}  {3,-6}  {4,-20}";

            m_log.InfoFormat(tableFormat, "Parcel name", "Position", "Glob X", "Glob Y", "Region name");
            foreach (BuyPoint bp in riverParcels)
            {
                m_log.InfoFormat(
                    tableFormat,
                    bp.Name, bp.Location.LocalPosition,
                    bp.Location.RegionX, bp.Location.RegionY, bp.Location.RegionName);
            }

            int allocateToEach = Math.Min(riverParcels.Count / farmers.Count, MAXIMUM_RIVER_PARCEL_ALLOCATION);

            m_log.InfoFormat("[WATER WARS]: Allocating {0} river parcels to each farmer", allocateToEach);

            // If there are spare parcels, then allocate river parcels surrounding the middle of the region.
            int startAllocationIndex = (int)Math.Ceiling((riverParcels.Count - farmers.Count * allocateToEach) / 2.0);

            m_log.InfoFormat("[WATER WARS]: Starting allocation at river parcel index {0}", startAllocationIndex);

            foreach (Player farmer in farmers)
            {
                int toAllocate = allocateToEach;
                while (toAllocate > 0)
                {
                    BuyPoint riverParcel = riverParcels[startAllocationIndex];

                    m_log.InfoFormat(
                        "[WATER WARS]: Allocating parcel {0} at {1} in {2} to {3}",
                        riverParcel.Name, riverParcel.Location.LocalPosition, riverParcel.Location.RegionName, farmer.Name);

                    state.AllocateParcel(riverParcel, farmer);

                    toAllocate--;
                    startAllocationIndex++;
                }

                m_controller.Events.PostModalMessage(
                    farmer.Uuid,
                    string.Format(
                        "As a farmer, you start the game already owning {0} parcels along the river.  In the environment, you can click on the farm buildings at each parcel to see which ones you own.",
                        allocateToEach));
            }

//            foreach (Player farmer in farmers)
//            {
//                int toAllocate = allocateToEach;
//                while (toAllocate > 0)
//                {
//                    BuyPoint riverParcel = riverParcels[WaterWarsUtils.Random.Next(0, riverParcels.Count)];
//                    if (riverParcel.HasAnyOwner)
//                        continue;
//
//                    m_log.InfoFormat(
//                        "[WATER WARS]: Allocating parcel {0} at {1} in {2} to {3}",
//                        riverParcel.Name, riverParcel.Location.LocalPosition, riverParcel.Location.RegionName, farmer.Name);
//
//                    state.AllocateParcel(riverParcel, farmer);
//                    toAllocate--;
//                }
//
//                m_controller.Events.PostModalMessage(
//                    farmer.Uuid,
//                    string.Format(
//                        "As a farmer, you start the game already owning {0} parcels along the river.  In the environment, you can click on the farm buildings at each parcel to see which ones you own.",
//                        allocateToEach));
//            }
        }
Esempio n. 24
0
 protected void RecordBuyPointReference(BuyPoint bp)
 {
     m_xtw.WriteStartElement(ParcelReferenceElement);
     RecordAttributes(bp);
     m_xtw.WriteEndElement();
 }
Esempio n. 25
0
 protected void AddCrops(BuyPoint bp)
 {
     c1 = (Crops)AddGameAsset(bp, 0, Crops.Template, 1);
 }
Esempio n. 26
0
 protected void ProcessParcelBought(BuyPoint bp, Player buyer)
 {
     ProcessGeneralParcelSold(
         bp, buyer, Player.None, RightsType.Combined, bp.CombinedPrice, bp.InitialWaterRights, true);
 }
Esempio n. 27
0
 protected void AddFactories(BuyPoint bp)
 {
     f1 = (Factory)AddGameAsset(bp, 0, Factory.Template, 2);
 }
Esempio n. 28
0
 protected void ProcessParcelSold(
     BuyPoint bp, Player buyer, Player seller, RightsType type, int price, bool success)
 {
     ProcessGeneralParcelSold(bp, buyer, seller, type, price, 0, success);
 }
Esempio n. 29
0
        public virtual void SetUp()
        {
            lo1 = new LandObject(UUID.Zero, false, null);
            lo2 = new LandObject(UUID.Zero, false, null);
            lo3 = new LandObject(UUID.Zero, false, null);

            bp1 = null; bp2 = null; bp3 = null;

            p1 = null; p2 = null;

            c1 = null;
            h1 = null; h2 = null; h3 = null;

            m_controller     = CreateController();
            m_mockDispatcher = new MockDispatcher(m_controller);
            m_mockDispatcher.Configuration = @"
[General]
start_date = 11/2/1904
seconds_per_stage = 0
rounds_per_game = 10
water_delivery_series = 1

[Players]
manufacturer_start_money = 17000
developer_start_money = 16000
farmer_start_money = 15000

manufacturer_cost_of_living = 0
developer_cost_of_living = 0
farmer_cost_of_living = 0

[Parcels]
rights_price = 350
water_entitlement = 1000

hill_zone_rights_price = 500
hill_zone_water_entitlement = 300

river_zone_rights_price = 1000
river_zone_water_entitlement = 900

[Crops]
alfalfa_cost_per_build_step = 50
chillis_cost_per_build_step = 30
grapes_cost_per_build_step = 80

alfalfa_build_steps = 1;
chillis_build_steps = 1;
grapes_build_steps = 1;

alfalfa_revenue = 100
chillis_revenue = 100
grapes_revenue = 40

alfalfa_maintenance = 0
chillis_maintenance = 0
grapes_maintenance = 0

alfalfa_water = 200
chillis_water = 500
grapes_water = 100

[Condos]
condos_1_cost_per_build_step = 50
condos_2_cost_per_build_step = 90
condos_3_cost_per_build_step = 120

condos_1_build_steps = 2;
condos_2_build_steps = 2;
condos_3_build_steps = 2;

condos_1_revenue = 150
condos_2_revenue = 200
condos_3_revenue = 250

condos_1_revenue_series = 1
condos_2_revenue_series = 1
condos_3_revenue_series = 1

condos_1_maintenance = 5
condos_2_maintenance = 4
condos_3_maintenance = 3

condos_1_water = 10
condos_2_water = 18
condos_3_water = 24

[Factories]
factories_1_cost_per_build_step = 5000
factories_2_cost_per_build_step = 7000
factories_3_cost_per_build_step = 9000

factories_1_build_steps = 1
factories_2_build_steps = 1
factories_3_build_steps = 1

factories_1_revenue = 2000
factories_2_revenue = 3000
factories_3_revenue = 4000

factories_revenue_series = 1

factories_1_maintenance = 500
factories_2_maintenance = 700
factories_3_maintenance = 900

factories_1_water = 1000
factories_2_water = 800
factories_3_water = 600";

            m_controller.Dispatcher = m_mockDispatcher;
            m_controller.Initialise(false);
        }
Esempio n. 30
0
        /// <summary>
        /// Randomly buys parcels for players.
        /// </summary>
        /// This exists only for testing
        /// <param name="parcelsToBuy">The total number of parcels to buy for all players.  Asset numbers are still uncontrolled</param>
        public void BuyRandom(int parcelsToBuy)
        {
            if (parcelsToBuy < 0)
            {
                throw new Exception("Number of parcels to buy must be greater than 0");
            }

            int boughtCount  = 0;
            int unownedCount = 0;

            List <BuyPoint> buyPoints;

            lock (m_controller.Game.BuyPoints)
                buyPoints = m_controller.Game.BuyPoints.Values.ToList();

            List <Player> players;

            lock (m_controller.Game.Players)
                players = m_controller.Game.Players.Values.ToList();

            foreach (BuyPoint bp in buyPoints)
            {
                if (bp.DevelopmentRightsOwner == Player.None)
                {
                    unownedCount++;
                }
            }

            // Constrained the number of parcels to buy to the number actually available
            if (unownedCount < parcelsToBuy)
            {
                parcelsToBuy = unownedCount;
            }

            m_log.InfoFormat("[WATER WARS]: Buy random buying {0} parcels", parcelsToBuy);

            try
            {
                while (boughtCount < parcelsToBuy)
                {
                    foreach (Player p in players)
                    {
                        AbstractGameAsset templateAsset = p.Role.AllowedAssets[0];
                        BuyPoint          bp            = buyPoints[WaterWarsUtils.Random.Next(0, buyPoints.Count)];

                        if (bp.DevelopmentRightsOwner == Player.None)
                        {
                            m_controller.State.BuyLandRights(bp, p);
                            boughtCount++;

                            int assetsToBuy;
                            lock (bp.Fields)
                                assetsToBuy = WaterWarsUtils.Random.Next(0, bp.Fields.Count) + 1;

                            while (assetsToBuy-- > 0)
                            {
                                Field f;
                                lock (bp.Fields)
                                    f = bp.Fields.Values.ToList()[WaterWarsUtils.Random.Next(0, bp.Fields.Count)];

                                bool foundExistingField = false;

                                lock (bp.GameAssets)
                                {
                                    // FIXME: This is the only way we can currently determine in game logic if a field
                                    // is currently visible or not!
                                    foreach (AbstractGameAsset ga in bp.GameAssets.Values)
                                    {
                                        if (ga.Field == f)
                                        {
                                            foundExistingField = true;
                                        }
                                    }
                                }

                                if (!foundExistingField)
                                {
                                    m_controller.State.BuildGameAsset(
                                        f, templateAsset, WaterWarsUtils.Random.Next(templateAsset.MinLevel, templateAsset.MaxLevel + 1));
                                }
                            }

                            break;
                        }
                    }
                }
            }
            catch (WaterWarsGameLogicException e)
            {
                // BuyLandRights throws this exception if player does not have enough money or for other
                // conditions.  This is not yet consistent across the board (e.g. BuyGameAsset doesn't do this).
                m_log.WarnFormat(
                    "[WATER WARS]: Buy random command finished with {0}{1}", e.Message, e.StackTrace);
            }

            m_log.InfoFormat(
                "[WATER WARS]: ww buy random command bought {0} parcels out of {1} unowned", boughtCount, unownedCount);
        }