public override void UndoUseWater(AbstractGameAsset a) { if (!a.CanBeAllocatedWater) { throw new WaterWarsGameLogicException( string.Format( "Attempt made to undo allocate water on asset {0} but this asset type does not allow water allocation", a.Name)); } if (!a.IsBuilt) { throw new WaterWarsGameLogicException( "{0} tried to undo allocate water on asset {1} but it is only partially built", a.OwnerName, a.Name); } Player p = a.Field.BuyPoint.DevelopmentRightsOwner; BuyPoint bp = a.Field.BuyPoint; m_log.InfoFormat( "[WATER WARS]: {0} undoing use of {1} on {2} at {3} in {4}", p.Name, WaterWarsUtils.GetWaterUnitsText(a.WaterAllocated), a.Name, bp.Name, bp.Location.RegionName); m_controller.WaterAllocator.ChangeAllocation(a, p, 0); m_controller.EventManager.TriggerWaterUsed(a, p, 0); a.TriggerChanged(); bp.TriggerChanged(); p.TriggerChanged(); UpdateHudStatus(p); }
protected override void PostStartState() { // Perform economic activity Game.EconomicActivity = m_controller.EconomicGenerator.Generate(Game); lock (Game.GameAssets) { Dictionary <AbstractGameAsset, int> allocation = m_controller.EconomicDistributor.Allocate(Game.EconomicActivity, Game.GameAssets.Values); foreach (AbstractGameAsset ga in allocation.Keys) { // Messy. This will need to come out as a separate Dictionary of market prices from the allocator // or perhaps another source (MarketPricer?) if (ga.Type == AbstractGameAssetType.Houses) { ga.MarketPrice = allocation[ga]; } else { ga.RevenueThisTurn = allocation[ga]; } } } // Perform water activity RainfallTotal = m_controller.RainfallGenerator.Generate(Game); m_controller.EventManager.TriggerWaterGenerated(RainfallTotal); m_log.InfoFormat( "[WATER WARS]: Generated {0} over {1} parcels", WaterWarsUtils.GetWaterUnitsText(RainfallTotal), Game.BuyPoints.Count); List <Player> players; lock (Game.Players) players = Game.Players.Values.ToList(); Dictionary <Player, int> waterAllocated = m_controller.WaterDistributor.Allocate(RainfallTotal, players, Game.BuyPoints.Values); foreach (Player p in waterAllocated.Keys) { p.WaterReceived = waterAllocated[p]; p.Water += p.WaterReceived; m_log.InfoFormat( "[WATER WARS]: Allocated {0} to {1}", WaterWarsUtils.GetWaterUnitsText(p.WaterReceived), p.Name); m_controller.EventManager.TriggerWaterAllocated(p, p.WaterReceived); // We'll leave it up to the following Water State (or possibly Reset State) to trigger the general // player data change event // p.TriggerChanged(); } EndState(new WaterStageState(m_controller)); }
protected void UpdateLabel() { if (m_controller.Game.State == GameStateType.Build) { LabelBehaviour.Text = string.Format("Rights owned\n{0}", WaterWarsUtils.GetWaterUnitsText(m_waterEntitlement)); } else { LabelBehaviour.Text = string.Format("Available for use\n{0}", WaterWarsUtils.GetWaterUnitsText(m_water)); } }
public override void GiveWaterRights(Player p, int amount) { m_log.InfoFormat("[WATER WARS]: Giving rights to {0} to {1}", WaterWarsUtils.GetWaterUnitsText(amount), p.Name); p.WaterEntitlement += amount; m_controller.EventManager.TriggerWaterRightsGiven(p, amount); p.TriggerChanged(); // FIXME: Should be done via event subscription. UpdateHudStatus(p); }
protected void AskBuyer() { SendDialog( m_buyer, string.Format( "Would you like to buy the rights to {0} from {1} for {2}{3}?", WaterWarsUtils.GetWaterUnitsText(m_amount), m_seller.Name, WaterWarsConstants.MONEY_UNIT, m_salePrice), YES_NO_OPTIONS, ProcessBuyer); SendAlert( m_seller, string.Format( "Offer to sell rights for {0} to {1} for {2}{3} has been sent", WaterWarsUtils.GetWaterUnitsText(m_amount), m_buyer.Name, WaterWarsConstants.MONEY_UNIT, m_salePrice)); }
protected Hashtable HandleBuyPointChange(string rawBpId, Hashtable request) { JObject json = GetJsonFromPost(request); string name = (string)json.SelectToken("Name"); bool changingName = name != null; string rawDevelopmentRightsBuyerId = (string)json.SelectToken("DevelopmentRightsOwner.Uuid.Guid"); bool buyingDevelopmentRights = rawDevelopmentRightsBuyerId != null; string rawWaterRightsBuyerId = (string)json.SelectToken("WaterRightsOwner.Uuid.Guid"); bool buyingWaterRights = rawWaterRightsBuyerId != null; int?developmentRightsPrice = (int?)json.SelectToken("DevelopmentRightsPrice"); int?waterRightsPrice = (int?)json.SelectToken("WaterRightsPrice"); int?combinedRightsPrice = (int?)json.SelectToken("CombinedPrice"); // m_log.InfoFormat( // "rawBpId [{0}], buyingDevelopmentRights [{1}], buyingWaterRights [{2}]", // rawBpId, buyingDevelopmentRights, buyingWaterRights); UUID bpId = WaterWarsUtils.ParseRawId(rawBpId); BuyPoint bp = null; m_controller.Game.BuyPoints.TryGetValue(bpId, out bp); if (changingName) { return(HandleChangeName(bp, name)); } else if (buyingDevelopmentRights || buyingWaterRights) { return(HandleBuyRights( bp, buyingDevelopmentRights, buyingWaterRights, rawDevelopmentRightsBuyerId, rawWaterRightsBuyerId, developmentRightsPrice, waterRightsPrice, combinedRightsPrice, request)); } // 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); }
protected void ProcessBuyer(OSChatMessage chat) { m_log.InfoFormat( "[WATER WARS]: Processing reply {0} for {1} selling to {2}", chat.Message, m_seller, m_buyer); bool accepted = false; if (YES_OPTION == chat.Message) { if (m_buyer.Money >= m_salePrice) { accepted = true; } else { SendAlert(m_buyer, "You don't have enough money to accept that offer!"); } } if (accepted) { m_controller.State.SellWaterRights(m_buyer, m_seller, m_amount, m_salePrice); SendAlert( m_seller, string.Format( "You successfully sold rights to {0} to {1} for {2}{3}", WaterWarsUtils.GetWaterUnitsText(m_amount), m_buyer.Name, WaterWarsConstants.MONEY_UNIT, m_salePrice)); SendAlert( m_buyer, string.Format( "You successfully bought the rights to {0} from {1} for {2}{3}", WaterWarsUtils.GetWaterUnitsText(m_amount), m_seller.Name, WaterWarsConstants.MONEY_UNIT, m_salePrice)); } else { m_controller.EventManager.TriggerWaterRightsSold(m_buyer, m_seller, m_amount, m_salePrice, false); SendAlert( m_seller, string.Format( "{0} declined your offer to sell them rights to {1} for {2}{3}", m_buyer.Name, WaterWarsUtils.GetWaterUnitsText(m_amount), WaterWarsConstants.MONEY_UNIT, m_salePrice)); } }
protected Hashtable HandleLogin(UUID playerId, Hashtable request) { Hashtable reply = new Hashtable(); // We have to give some response string otherwise the return code crashes reply["str_response_string"] = ""; UUID loginToken = UUID.Zero; lock (m_loginTokens) m_loginTokens.TryGetValue(playerId, out loginToken); bool passed = false; if (!WaterWarsConstants.IS_WEBSERVICE_SECURITY_ON) { passed = true; } else { UUID submittedLoginToken = WaterWarsUtils.ParseRawId((string)request["loginToken"]); if (loginToken == submittedLoginToken) { passed = true; } } if (passed) { reply["int_response_code"] = 200; lock (m_loginTokens) m_loginTokens.Remove(playerId); // TODO: Establish the second authorization token } else { reply["int_response_code"] = 401; } return(reply); }
public override void SellWaterRights(Player buyer, Player seller, int amount, int salePrice) { if (buyer.Money < salePrice) { throw new WaterWarsGameLogicException( string.Format( "Player {0} tried to buy {1} water rights from {2} for {3} but they only have {4}", buyer, amount, seller, salePrice, buyer.Money)); } if (seller.WaterEntitlement < amount) { throw new WaterWarsGameLogicException( string.Format( "Player {0} tried to sell {1} water rights to {2} but they only have {3}", seller, amount, buyer, WaterWarsUtils.GetWaterUnitsText(seller.WaterEntitlement))); } m_log.InfoFormat( "[WATER WARS]: Player {0} selling {1} water rights to {2} for {3}", seller, amount, buyer, salePrice); buyer.Money -= salePrice; buyer.WaterRightsCostsThisTurn += salePrice; seller.Money += salePrice; seller.WaterRightsRevenueThisTurn += salePrice; buyer.WaterEntitlement += amount; seller.WaterEntitlement -= amount; m_controller.EventManager.TriggerWaterRightsSold(buyer, seller, amount, salePrice, true); buyer.TriggerChanged(); seller.TriggerChanged(); // FIXME: Should be done via event subscription. UpdateHudStatus(buyer); UpdateHudStatus(seller); m_controller.Events.PostToAll( string.Format(SELL_WATER_RIGHTS_CRAWL_MSG, seller.Name, WaterWarsUtils.GetWaterUnitsText(amount), buyer.Name), EventLevel.Crawl); }
public override void SellWater(Player seller, Player buyer, int water, int price) { if (seller.Water < water) { throw new WaterWarsGameLogicException( string.Format( "{0} only has {1} but is trying to sell {2} to {3}", seller, WaterWarsUtils.GetWaterUnitsText(seller.Water), WaterWarsUtils.GetWaterUnitsText(water), buyer)); } if (buyer.Money < price) { throw new WaterWarsGameLogicException( string.Format( "{0} only has {1} but {2} is trying to sell them water for {3}", buyer, buyer.Money, seller, price)); } m_log.InfoFormat( "[WATER WARS]: {0} selling {1} to {2} for {3}", seller.Name, WaterWarsUtils.GetWaterUnitsText(water), buyer.Name, price); seller.Money += price; buyer.Money -= price; buyer.WaterCostsThisTurn += price; seller.WaterRevenueThisTurn += price; seller.Water -= water; buyer.Water += water; m_controller.EventManager.TriggerWaterSold(buyer, seller, water, price, true); buyer.TriggerChanged(); seller.TriggerChanged(); UpdateHudStatus(seller); UpdateHudStatus(buyer); m_controller.Events.PostToAll( string.Format( SELL_WATER_CRAWL_MSG, seller.Name, WaterWarsUtils.GetWaterUnitsText(water), buyer.Name), EventLevel.Crawl); }
public override void RegisterBuyPoint(BuyPoint bp) { Vector3 swPoint, nePoint; WaterWarsUtils.FindSquareParcelCorners(bp.Location.Parcel, out swPoint, out nePoint); if (!Game.BuyPoints.ContainsKey(bp.Uuid)) { m_log.InfoFormat( "[WATER WARS]: Registering buy point {0} named {1} at {2} in parcel {3} ({4},{5})", bp.Uuid, bp.Name, bp.Location.LocalPosition, bp.Location.Parcel.LandData.Name, swPoint, nePoint); Game.BuyPoints[bp.Uuid] = bp; } else { m_log.WarnFormat( "[WATER WARS]: Attempt to register duplicate buy point {0} named {1} at {2} in parcel {3} ({4},{5})", bp.Uuid, bp.Name, bp.Location.LocalPosition, bp.Location.Parcel.LandData.Name, swPoint, nePoint); } m_controller.EventManager.TriggerBuyPointRegistered(bp); }
protected override void StartState() { base.StartState(); // We do not provide a forecast for the next water phase during the current water phase. Game.Forecast.Economic = null; Game.Forecast.Water = "Available next build phase"; List <Player> players; lock (Game.Players) players = Game.Players.Values.ToList(); foreach (Player p in players) { m_controller.Events.Post( p, string.Format(FEED_RAINFALL_MSG, WaterWarsUtils.GetWaterUnitsText(p.WaterReceived)), EventLevel.Alert); } UpdateAllStatus(); }
public override void UseWater(AbstractGameAsset a, Player p, int amount) { BuyPoint bp = a.Field.BuyPoint; if (bp.DevelopmentRightsOwner != p) { throw new WaterWarsGameLogicException( "{0} tried to allocate water on asset {1} but development rights are owned by {2}", p, a, bp.DevelopmentRightsOwner); } if (!a.CanBeAllocatedWater) { throw new WaterWarsGameLogicException( "{0} tried to allocate water on asset {1} but this asset type does not allow water allocation", p.Name, a.Name); } if (!a.IsBuilt) { throw new WaterWarsGameLogicException( "{0} tried to allocate water on asset {1} but it is only partially built", p.Name, a.Name); } m_log.InfoFormat( "[WATER WARS]: {0} using {1} on {2} at {3} in {4}", p.Name, WaterWarsUtils.GetWaterUnitsText(amount), a.Name, bp.Name, bp.Location.RegionName); m_controller.WaterAllocator.ChangeAllocation(a, p, amount); m_controller.EventManager.TriggerWaterUsed(a, p, amount); a.TriggerChanged(); bp.TriggerChanged(); p.TriggerChanged(); UpdateHudStatus(p); }
/// <summary> /// Change the specialization presentation of this buy point view /// </summary> /// <param name="assetType"></param> /// <param name="fields">Fields for which field views need to be created</param> public Dictionary <UUID, FieldView> ChangeSpecialization(AbstractGameAssetType assetType, List <Field> fields) { Dictionary <UUID, FieldView> fvs = new Dictionary <UUID, FieldView>(); string morphItemName = m_veSceneObjectNames[assetType]; ChangeSceneObject(m_itemStoreView, morphItemName); m_bp.Name = morphItemName; if (assetType != AbstractGameAssetType.None) { Vector3 p1, p2; WaterWarsUtils.FindSquareParcelCorners(m_bp.Location.Parcel, out p1, out p2); // m_log.InfoFormat("[WATER WARS]: Found corners of parcel at ({0}),({1})", p1, p2); int shortDimension = (int)Math.Floor(Math.Sqrt(fields.Count)); int longDimension = (int)Math.Ceiling((float)fields.Count / shortDimension); // m_log.InfoFormat("[WATER WARS]: Would space as [{0}][{1}]", shortDimension, longDimension); // XXX: For now, we're always going to short space the fields on the x axis // This shouldn't be a problem if all our regions are square but might start to look a bit odd if they // were different rectangular sizes // Adjust dimensions to leave a gap around the edges for the buypoint p1.X += 5; p1.Y += 5; p2.X -= 5; p2.Y -= 5; float xSpacing = (p2.X - p1.X) / (float)shortDimension; float ySpacing = (p2.Y - p1.Y) / (float)longDimension; List <Vector3> placementPoints = new List <Vector3>(); // for (int y = y1; y < y2; y += ySpacing) // { // for (float x = x1; x < x2; x += xSpacing) // { // placementPoints.Add(new Vector3(x, y, (float)heightHere + 0.1f)); // } // } for (int y = 0; y < longDimension; y++) { for (float x = 0; x < shortDimension; x++) { Vector3 spacing = new Vector3(x * xSpacing, y * ySpacing, 2f); placementPoints.Add(p1 + spacing); } } m_fieldViewScale = new Vector3(xSpacing, ySpacing, 0.1f); Vector3 placementAdjustment = new Vector3(xSpacing / 2, ySpacing / 2, 0); int i = 0; foreach (Vector3 v in placementPoints) { FieldView fv = CreateFieldView(fields[i++], v + placementAdjustment); fvs.Add(fv.RootPart.UUID, fv); } } else { lock (m_fieldViews) { foreach (FieldView fv in m_fieldViews.Values) { fv.Close(); } m_fieldViews.Clear(); } } return(fvs); }
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); }
protected override void PostStartState() { Dictionary <Player, int> eotRevenues = CalculateOperatingRevenue(); Dictionary <Player, int> eotCosts = CalculateMaintenanceCosts(); Dictionary <Player, string> eotMessages = new Dictionary <Player, string>(); foreach (Player p in Game.Players.Values) { // Right now we also want to reset all water the player has in hand. // TODO: This should be a separate rule p.Water = 0; p.Money += eotRevenues[p]; p.Money -= eotCosts[p]; p.Money -= p.CostOfLiving; m_controller.EventManager.TriggerRevenueReceived(p, eotRevenues[p], eotCosts[p], p.CostOfLiving); p.RecordHistory(); int revenue = 0, costs = 0, capitalRevenue = 0, capitalCosts = 0; // Common financial components revenue = p.WaterRevenueThisTurn; costs = p.MaintenanceCosts + p.WaterCostsThisTurn + p.CostOfLiving; capitalRevenue = p.LandRevenueThisTurn + p.WaterRightsRevenueThisTurn; capitalCosts = p.LandCostsThisTurn + p.WaterRightsCostsThisTurn; if (p.Role.Type == RoleType.Farmer) { revenue += p.ProjectedRevenueFromProducts; costs += p.BuildCostsThisTurn; } else if (p.Role.Type == RoleType.Developer) { revenue += p.BuildRevenueThisTurn; costs += p.BuildCostsThisTurn; } else if (p.Role.Type == RoleType.Manufacturer) { revenue += p.ProjectedRevenueFromProducts; capitalCosts += p.BuildCostsThisTurn; } int profit = revenue - costs; string profitText = WaterWarsUtils.GetMoneyUnitsText(profit); string revenueText = WaterWarsUtils.GetMoneyUnitsText(revenue); string costsText = WaterWarsUtils.GetMoneyUnitsText(costs); string capitalRevenueText = WaterWarsUtils.GetMoneyUnitsText(capitalRevenue); string capitalCostsText = WaterWarsUtils.GetMoneyUnitsText(capitalCosts); m_log.InfoFormat( "[WATER WARS]: {0} made {1} ({2} revenue - {3} costs) this turn, excluding {4} capital revenue, {5} capital costs", p.Name, profitText, revenueText, costsText, capitalRevenueText, capitalCostsText); string msg = string.Format(REVENUE_AND_COST_MSG, profitText) + "\n"; // string msg = string.Format( // REVENUE_AND_COST_MSG, profitText, revenueText, costsText, capitalCostsText) + "\n"; if (m_controller.Game.IsLastRound) { msg += GAME_ENDED_STATUS_MSG; } else { msg += BuildStageState.BUILD_PHASE_STARTING_MSG; } eotMessages[p] = msg; } // Do these actions after recording history so that project revenues (based on ga allocations) are correct List <AbstractGameAsset> assetsRemoved = AgeGameAssets(); foreach (Player p in Game.Players.Values) { m_controller.Events.Post(p, eotMessages[p], EventLevel.All); } ResetPerTurnProperties(); m_controller.EventManager.TriggerRevenueStageEnded(assetsRemoved); if (!m_controller.RoundManager.EndRound()) { m_controller.GameDateManager.AdvanceDate(); EndState(new BuildStageState(m_controller)); } else { EndState(new GameEndedState(m_controller)); } }