diff --git a/TODO.taskpaper b/TODO.taskpaper --- a/TODO.taskpaper +++ b/TODO.taskpaper @@ -2,7 +2,7 @@ Gameplay: Money: - Add basic subsidy @milestone(1: Basic Money) @done(2021-01-27) - - Balance sheet + - Basic Balance sheet - Basic balance sheet @milestone(1: Basic Money) - Basic display @done(2021-01-27) - Movement @done(2021-01-27) @@ -16,7 +16,7 @@ - Outline reserved areas @milestone(3: Contracts) - Trees: - - Add basic maintenance cost @milestone(1: Basic Money) + - Add basic maintenance cost @milestone(1: Basic Money) @done(2021-01-27) - Add basic age simulation - Biodiversity @maybe - Research agreements @maybe @@ -67,8 +67,8 @@ Other features: Accessibility: - Verify contrast - - Increase display size - - Turn off bad outcomes + - Option to Increase display size + - Option to Turn off bad outcomes or disasters? Other QoL things: - Adjust display size - Toggle trees translucency diff --git a/isometric-park-fna/CellMap.cs b/isometric-park-fna/CellMap.cs --- a/isometric-park-fna/CellMap.cs +++ b/isometric-park-fna/CellMap.cs @@ -31,6 +31,23 @@ } } + public int tree_capacity + { + get + { + return MapWidth * MapHeight; + } + } + + public int remaining_tree_capacity + { + get + { + return this.tree_capacity - this.tree_count; + } + } + + public CellMap() { //TileMap(MapWidth, MapHeight); @@ -56,7 +73,7 @@ } - public System.Collections.IEnumerable tree_cells() + public System.Collections.Generic.IEnumerable tree_cells() { foreach (List row in cells) { @@ -70,7 +87,7 @@ } } - public System.Collections.IEnumerable tree_cells(int zone) + public System.Collections.Generic.IEnumerable tree_cells(int zone) { foreach (List row in cells) { @@ -84,7 +101,7 @@ } } - public System.Collections.IEnumerable iterate_cells() + public System.Collections.Generic.IEnumerable iterate_cells() { foreach (List row in cells) { @@ -100,7 +117,7 @@ return MathUtils.Between(x, 0, MapWidth - 1) && MathUtils.Between(y, 0, MapHeight - 1); } - private System.Collections.IEnumerable iterate_neighbors(int x, int y) + private System.Collections.Generic.IEnumerable iterate_neighbors(int x, int y) { //iterates over neighbors (clockwise starting at noon/midnight) if (inBounds(x, y + 1)) @@ -142,13 +159,15 @@ int count = 0; foreach (Cell neighbor in this.iterate_neighbors(x, y)) { - count++; + if (neighbor.hasTree) { + count++; + } } return count; } - public System.Collections.IEnumerable iterate_cells_with_neighbors(int neighbors) + public System.Collections.Generic.IEnumerable iterate_cells_with_neighbors(int neighbors) { for (int i = 0; i < MapHeight; i++) { @@ -165,9 +184,41 @@ } + public enum CellStatus{ + Clear, + LivingTree, + DeadTree + } + public class Cell { - public Boolean hasTree = false; + // public Boolean _hasTree = false; + public CellStatus status { + get; + private set; + } + + public Boolean hasTree { + get { + return this.status == CellStatus.LivingTree; + } + } + + public DateTime planted; + + public void addTree(DateTime datetime) { + this.status = CellStatus.LivingTree; + + this.planted = datetime; + } + + public void removeTree() { + this.status = CellStatus.Clear; + } + + public void markTreeDead() { + this.status = CellStatus.DeadTree; + } } } } \ No newline at end of file diff --git a/isometric-park-fna/FNAGame.cs b/isometric-park-fna/FNAGame.cs --- a/isometric-park-fna/FNAGame.cs +++ b/isometric-park-fna/FNAGame.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Input; @@ -14,6 +14,7 @@ using System.Diagnostics; using static isometricparkfna.CellMap; using isometricparkfna.Utils; +using isometricparkfna.UI; @@ -71,10 +72,13 @@ private Queue> remainingDialog; - private bool showGrid = true; + private bool showGrid; private Grammar grammar; private string output; private GraphicsDeviceManager gdm; + private bool showBudget; + private BudgetWindow budgetWindow; + private bool showForest; private static void Main(string[] args) { @@ -115,13 +119,20 @@ { if (this.random_generator.NextDouble() > 0.75) { - cell.hasTree = true; + int random_year = (int)MathHelper.Clamp((float)MathUtils.NextNormal(random_generator, 2010.0f, 40.0f), 1800, Simulation.START_YEAR); + int random_month = random_generator.Next(1, 12); + DateTime random_date = new DateTime(random_year, random_month, 1); + + cell.addTree(random_date); } } } showInitial = true; messageIndex = 0; + showBudget = false; + showForest = true; + showGrid = true; this.Window.Title = "Isometric Park"; @@ -129,8 +140,6 @@ currentNode = DialogTrees.introTree; - - } protected override void Initialize() @@ -188,6 +197,9 @@ //font = fontBakeResult.CreateSpriteFont(GraphicsDevice); monoFont = bakedMono.CreateSpriteFont(GraphicsDevice); + this.budgetWindow = new BudgetWindow(new Budget { }, this.monoFont, 0, 0); + + } protected override void UnloadContent() @@ -323,6 +335,16 @@ this.showGrid = !this.showGrid; } + if (keyboardCur.IsKeyDown(Keys.B) && keyboardPrev.IsKeyUp(Keys.B)) + { + this.showBudget = !this.showBudget; + + } + if (keyboardCur.IsKeyDown(Keys.F) && keyboardPrev.IsKeyUp(Keys.F)) + { + this.showForest = !this.showForest; + + } if (keyboardCur.IsKeyDown(Keys.C) && keyboardPrev.IsKeyUp(Keys.C)) { this.camera.Jump(Vector2.Zero); @@ -387,8 +409,15 @@ #endregion input + + this.simulation.update(gameTime.ElapsedGameTime); + if (this.showBudget) + { + this.showBudget = this.budgetWindow.update(mouseCur, this.simulation.latestBudget, this.simulation.previousBudget); + } + if (!this.showInitial && this.remainingDialog.Count > 0) { @@ -673,15 +702,21 @@ if (this.simulation.map.cells[i][j].hasTree) { //until we actually simulate: - if ((i + j) % 8 == 0) - { + drawTileAt(i, j, 142, 2); + // if ((i + j) % 8 == 0) + // { + // drawTileAt(i, j, 141, 2); + // } + // else + // { + // drawTileAt(i, j, 142, 2); + // } + } + else if (this.simulation.map.cells[i][j].status == CellStatus.DeadTree) { drawTileAt(i, j, 141, 2); - } - else - { - drawTileAt(i, j, 142, 2); - } - } + // System.Console.WriteLine(String.Format("Drew Dead Tree at {0},{1}", i, j)); + + } } } #endregion draw_trees @@ -716,17 +751,30 @@ this.Window.Title = String.Format("Isometric Park [{0:}]", header_middle); Vector2 dimensions = monoFont.MeasureString(header_middle); - float middle_start = (FNAGame.width / 2) - (dimensions.X / 2); + float middle_start = (int)((FNAGame.width / 2) - (dimensions.X / 2)); FilledRectangle.drawFilledRectangle(batch, new Rectangle(0, 0, width, (int)dimensions.Y), Color.White, 0.51f); batch.DrawString(monoFont, header_left, new Vector2(1, 1), Color.Black, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.5f); batch.DrawString(monoFont, header_middle, new Vector2(middle_start, 1), Color.Black, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.5f); -#endregion draw_header + #endregion draw_header - batch.End(); + #region budget + + if (this.showBudget) + { + budgetWindow.draw(batch); + + } + + #endregion budget + + batch.End(); + + + #region debug_window //Calcs for debug window: @@ -763,11 +811,11 @@ additionalInfo.Add("mouse delta", delta.ToString()); additionalInfo.Add("Tracery Test", this.output); - debugWindow.Layout(debugInfo, additionalInfo, ref show_another_window); + + debugWindow.Layout(debugInfo, additionalInfo, ref show_another_window); - debugWindow.ImGuiLayout(); - + //debugWindow.ImGuiLayout(); //String[] messages = { "Message1", "Message2" }; //DialogOption[] dialog = { new DialogOption{ response="Welcome to your new park, director! You can use the mouse or arrow keys to move around, and the plus and minus keys to zoom in and out.", choice="Okay" }, @@ -781,6 +829,11 @@ ref this.simulation.paused, debugWindow.monoFont, this.currentNode); } + if (this.showForest) + { + ForestWindow.Render(ref this.showForest, debugWindow.monoFont, this.simulation); + } + _imGuiRenderer.AfterLayout(); diff --git a/isometric-park-fna/Simulation.cs b/isometric-park-fna/Simulation.cs --- a/isometric-park-fna/Simulation.cs +++ b/isometric-park-fna/Simulation.cs @@ -1,19 +1,58 @@ -using System; +using System; +using System.Collections.Generic; using static isometricparkfna.CellMap; +using System.Linq; namespace isometricparkfna { + public struct Budget + { + public DateTime DateTime; + + //assets + public decimal money; + + + //revenue + public decimal subsidy; + + //expenses + public decimal upkeep; + public decimal tree_planting; + public decimal tree_clearing; + + + public decimal final_money; + public decimal cashflow; + + + //misc + public int trees; + + } + public class Simulation { public const int START_YEAR = 2020; public const int START_MONTH = 1; public const int START_DAY = 1; + public DateTime START_DATETIME{ + get { + return new DateTime(START_YEAR, START_MONTH, START_DAY); + }} + private const float SPONTANEOUS_NEW_TREE_CHANCE = 0.9995f; private const float NEIGHBOR_NEW_TREE_CHANCE = 0.995f; private const float NEIGHBOR_CROWDS_TREE_CHANCE = 0.995f; + public const int TREE_PLANT_COST = 750; + public const int TREE_CLEAR_COST = 500; + + public const int MAX_TREES_TO_PLANT = 25; + public const int MAX_TREES_TO_CLEAR = 25; + public int Tick { get; @@ -37,6 +76,39 @@ public decimal money; + private List budgets; + + + public Budget latestBudget + { + get + { + if (this.budgets.Count >= 1) { + return this.budgets[this.budgets.Count - 1]; + + } + else + { + return new Budget { }; + } + } + } + + public Budget previousBudget + { + get + { + if (this.budgets.Count >= 2) { + return this.budgets[this.budgets.Count - 2]; + + } + else + { + return new Budget { }; + } + } + } + public float millisecondsPerAdvance { get; private set; } public String Season { get { @@ -65,7 +137,62 @@ private float lastAdvance; public bool paused; - private Random random; + private Random random; + + //forest policy params + private int _tree_planting; + public int tree_planting + { + get { + return _tree_planting; + } + set { + _tree_planting = MathUtils.Clamp(value, 0, MAX_TREES_TO_PLANT); + } + } + private int _tree_clearing = 0; + public int tree_clearing + { + get { + return _tree_clearing; + } + set { + _tree_clearing = MathUtils.Clamp(value, 0, MAX_TREES_TO_CLEAR); + } + } + + public int crowded_trees + { + get { + return this.map.iterate_cells_with_neighbors(7).Where(c => c.hasTree).Count(); + + } + } + + public float healthy_percent + { + get { + return (float)(this.map.tree_count - this.map.iterate_cells_with_neighbors(7).Where(c => c.hasTree).Count()) / this.map.tree_count * 100; + } + } + + public double average_tree_age + { + get + { + return this.map.iterate_cells().Where(c => c.hasTree).Select(c => (this.DateTime - c.planted).Days / 365.0).Average(); + } + } + + public double max_tree_age + { + get + { + return this.map.iterate_cells().Where(c => c.hasTree).Select(c => (this.DateTime - c.planted).Days / 365.0).Max(); + } + } + + public Simulation(int width, int height, float millisecondsPerAdvance) { @@ -74,10 +201,12 @@ this.DateTime = new DateTime(START_YEAR, START_MONTH, START_DAY); this.map = new CellMap(width, height); - this.money = 1000; + this.money = 100000; this.millisecondsPerAdvance = millisecondsPerAdvance; this.paused = true; + + this.budgets = new List(); } private void advanceSimulation() @@ -85,30 +214,91 @@ this.DateTime = this.DateTime.AddMonths(1); + foreach (Cell cell in this.map.iterate_cells()) { if (random.NextDouble() > SPONTANEOUS_NEW_TREE_CHANCE) { - cell.hasTree = true; + cell.addTree(this.DateTime); } } + int new_planted = 0; foreach (Cell cell in this.map.iterate_cells_with_neighbors(4)) { if (random.NextDouble() > NEIGHBOR_NEW_TREE_CHANCE) { - cell.hasTree = true; + cell.addTree(this.DateTime); + new_planted += 1; } } + System.Console.WriteLine(String.Format("New {0}", new_planted)); + int crowded_out = 0; foreach (Cell cell in this.map.iterate_cells_with_neighbors(7)) { if (random.NextDouble() > NEIGHBOR_CROWDS_TREE_CHANCE) { - cell.hasTree = false; + cell.markTreeDead(); + crowded_out += 1; + } + } + System.Console.Write(String.Format("Crowded {0}", crowded_out)); + + int trees_to_plant = this.tree_planting; + + while (trees_to_plant > 0 && this.map.remaining_tree_capacity > 0) { + int y = random.Next(0, this.map.MapHeight); + int x = random.Next(0, this.map.MapWidth); + Cell chosen_cell = this.map.cells[x][y]; + + if (!chosen_cell.hasTree) { + chosen_cell.addTree(this.DateTime); + trees_to_plant -= 1; + } + } + + + int trees_to_clear = this.tree_clearing; + System.Console.Write(String.Format("Found {0}; ", this.map.iterate_cells_with_neighbors(7).Where(c => c.hasTree).Count())); + foreach (Cell cell in this.map.iterate_cells_with_neighbors(7).Where(c => c.hasTree)) + { + if (trees_to_clear > 0) { + cell.removeTree(); + trees_to_clear -= 1; } } + + Budget newBudget = new Budget + { + DateTime = this.DateTime, + money = this.money, + trees = this.map.tree_count, + subsidy = 1000, + upkeep = this.map.tree_count * 1, + tree_planting = this.tree_planting * Simulation.TREE_PLANT_COST, + tree_clearing = this.tree_clearing * Simulation.TREE_CLEAR_COST + }; + + + newBudget = this.applyBudget(newBudget); ; + this.budgets.Add(newBudget); } + + public Budget applyBudget(Budget budget) + { + + this.money = budget.money + - (budget.upkeep + budget.tree_planting + budget.tree_clearing) + + (budget.subsidy); + + + budget.final_money = this.money; + budget.cashflow = budget.final_money - budget.money; + + return budget; + } + public void update(TimeSpan deltaTime) { //this.Tick++; diff --git a/isometric-park-fna/UI/BudgetWindow.cs b/isometric-park-fna/UI/BudgetWindow.cs new file mode 100644 --- /dev/null +++ b/isometric-park-fna/UI/BudgetWindow.cs @@ -0,0 +1,130 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; + +namespace isometricparkfna.UI +{ + public class BudgetWindow + { + private Budget budget; + private Budget previous_budget; + private SpriteFont font; + public int x; + public int y; + + + private Vector2 mouseEnd; + private Vector2 mouseStart; + private MouseState mousePrev; + + private static int bar_height = 25; + private static int height = 500; + private static int width = 700; + + public BudgetWindow(Budget budget, SpriteFont font, int start_x, int start_y) + { + + this.budget = budget; + this.font = font; + this.x = start_x; + this.y = start_y; + } + + public bool update(MouseState mouseCur, Budget budget, Budget previous_budget) + { + this.budget = budget; + this.previous_budget = previous_budget; + + if ((mouseCur.LeftButton == ButtonState.Pressed) + && MathUtils.Between(mouseCur.X, width+x-20, width+x) + && MathUtils.Between(mouseCur.Y, y+bar_height, y+bar_height+20) + ) { + + return false; + + } + else if ((mouseCur.LeftButton == ButtonState.Pressed) + && MathUtils.Between(mouseCur.X, x, width+x) + && MathUtils.Between(mouseCur.Y, y, 500 + y)) + { + if (mousePrev.LeftButton == ButtonState.Released) + { + this.mouseStart = new Vector2(mouseCur.X, mouseCur.Y); + + } + else + { + this.mouseEnd = new Vector2(mouseCur.X, mouseCur.Y); + this.x = MathUtils.Clamp(this.x + (int)(this.mouseEnd.X - this.mouseStart.X), 0, width); + this.y = MathUtils.Clamp(this.y + (int)(this.mouseEnd.Y - this.mouseStart.Y), 0, 400); + } + } + + this.mouseStart = new Vector2(mouseCur.X, mouseCur.Y); + + this.mousePrev = mouseCur; + + return true; + } + + public void draw(SpriteBatch batch) + { + + + + FilledRectangle.drawFilledRectangle(batch, new Rectangle(x - 20, y+bar_height, 20, height), Color.White); + Line.drawLine(batch, new Vector2(x, y + bar_height), new Vector2(x, y + bar_height + height), Color.Gray); + FilledRectangle.drawFilledRectangle(batch, new Rectangle(x + width, y+bar_height, 20, height), Color.White); + Line.drawLine(batch, new Vector2(x + width, y + bar_height), new Vector2(x + width, y + bar_height + height), Color.Gray); + + for (int i = 1; i <= (height / bar_height); i++) + { + Rectangle position = new Rectangle(this.x, bar_height * i + this.y, + width, bar_height); + + if ((i % 2) == 0) + { + FilledRectangle.drawFilledRectangle(batch, position, Color.LightGreen, 0.99f); + } + else + { + FilledRectangle.drawFilledRectangle(batch, position, Color.White, 0.99f); + } + } + + FilledRectangle.drawFilledRectangle(batch, new Rectangle(x + width - 20, y+bar_height, 20, 20), Color.LightGray); + Vector2 dimensions = font.MeasureString("X"); + batch.DrawString(font, "X", new Vector2(x+width -20 + (dimensions.X/2), y+bar_height), Color.Black); + + batch.DrawString(font, String.Format("BUDGET REPORT FOR {0:MMMMM yyyy}", this.budget.DateTime), new Vector2(x, bar_height * 1 + y), Color.Black); + + batch.DrawString(font, String.Format("Starting Funds.........${0:}", this.budget.money), new Vector2(x, bar_height * 2 + y), Color.Black); + + batch.DrawString(font, String.Format("REVENUE", this.budget.upkeep), new Vector2(x, bar_height * 4 + y), Color.Black); + batch.DrawString(font, String.Format("Subsidy................${0:}....${1:}", this.budget.subsidy, this.previous_budget.subsidy), new Vector2(x, bar_height * 5 + y), Color.Black); + + batch.DrawString(font, String.Format("EXPENSES", this.budget.upkeep), new Vector2(x, bar_height * 9 + y), Color.Black); + batch.DrawString(font, String.Format("Upkeep.................${0:}....${1:}", this.budget.upkeep, this.previous_budget.upkeep), new Vector2(x, bar_height * 10 + y), Color.Black); + batch.DrawString(font, String.Format("Tree Planting..........${0:}....${1:}", this.budget.tree_planting, this.previous_budget.tree_planting), new Vector2(x, bar_height * 11 + y), Color.Black); + batch.DrawString(font, String.Format("Tree Clearing..........${0:}....${1:}", this.budget.tree_clearing, this.previous_budget.tree_clearing), new Vector2(x, bar_height * 12 + y), Color.Black); + + Color cashflow_color = Color.Black; + if (this.budget.cashflow < 0) { + cashflow_color = Color.Red; + } + Color final_color = Color.Black; + if (this.budget.final_money < 0) { + final_color = Color.Red; + } + + batch.DrawString(font, String.Format("Cashflow.............${0:}....${1:}", this.budget.cashflow, this.previous_budget.cashflow), new Vector2(x, bar_height * 14 + y), cashflow_color); + batch.DrawString(font, String.Format("Ending Funds.........${0:}....${1:}", this.budget.final_money, this.previous_budget.final_money), new Vector2(x, bar_height * 15 + y), final_color); + + + FilledRectangle.drawFilledRectangle(batch, new Rectangle(50, 50, 50, 50), new Color (0, 0,0, 0), 0.99f); + + + } + } +} diff --git a/isometric-park-fna/DebugWindow.cs b/isometric-park-fna/UI/DebugWindow.cs rename from isometric-park-fna/DebugWindow.cs rename to isometric-park-fna/UI/DebugWindow.cs --- a/isometric-park-fna/DebugWindow.cs +++ b/isometric-park-fna/UI/DebugWindow.cs @@ -7,7 +7,7 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -namespace isometricparkfna +namespace isometricparkfna.UI { public struct DebugInfo diff --git a/isometric-park-fna/Dialog.cs b/isometric-park-fna/UI/Dialog.cs rename from isometric-park-fna/Dialog.cs rename to isometric-park-fna/UI/Dialog.cs --- a/isometric-park-fna/Dialog.cs +++ b/isometric-park-fna/UI/Dialog.cs @@ -6,7 +6,7 @@ using Num = System.Numerics; -namespace isometricparkfna +namespace isometricparkfna.UI { @@ -110,6 +110,7 @@ { ImGui.PushFont(font); + ImGui.GetStyle().WindowMenuButtonPosition = ImGuiDir.None; ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 0.0f); ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 0.0f); ImGui.PushStyleVar(ImGuiStyleVar.FrameBorderSize, 1.0f); @@ -163,6 +164,7 @@ } ImGui.End(); + ImGui.GetStyle().WindowMenuButtonPosition = ImGuiDir.Left; ImGui.PopStyleVar(3); ImGui.PopStyleColor(8); ImGui.PopFont(); diff --git a/isometric-park-fna/UI/ForestWindow.cs b/isometric-park-fna/UI/ForestWindow.cs new file mode 100644 --- /dev/null +++ b/isometric-park-fna/UI/ForestWindow.cs @@ -0,0 +1,63 @@ +using ImGuiNET; + +using Num = System.Numerics; + +namespace isometricparkfna.UI +{ + + public static class ForestWindow + { + public static void Render(ref bool show, ImFontPtr font, Simulation sim) + { + if (show) + { + ImGui.PushFont(font); + + ImGui.GetStyle().WindowMenuButtonPosition = ImGuiDir.None; + ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 0.0f); + ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 0.0f); + ImGui.PushStyleVar(ImGuiStyleVar.FrameBorderSize, 1.0f); + ImGui.PushStyleColor(ImGuiCol.WindowBg, new Num.Vector4(0.75f, 0.75f, 0.75f, 1f)); + + var title_bar = new Num.Vector4(0.65f, 0.65f, 0.65f, 1f); + ImGui.PushStyleColor(ImGuiCol.TitleBg, title_bar); + ImGui.PushStyleColor(ImGuiCol.TitleBgActive, title_bar); + ImGui.PushStyleColor(ImGuiCol.TitleBgCollapsed, title_bar); + + ImGui.PushStyleColor(ImGuiCol.Border, new Num.Vector4(0f, 0f, 0f, 1f)); + ImGui.PushStyleColor(ImGuiCol.BorderShadow, new Num.Vector4(0f, 0f, 0f, 0.5f)); + + + + ImGui.PushStyleColor(ImGuiCol.Button, new Num.Vector4(0.75f, 0.75f, 0.75f, 1f)); + ImGui.PushStyleColor(ImGuiCol.Text, new Num.Vector4(0f, 0f, 0f, 1f)); + ImGui.Begin("Forest Policy", ref show, ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoSavedSettings); + + + int new_tree_planting = sim.tree_planting; + ImGui.SliderInt("Tree Planting ", ref new_tree_planting, 0, Simulation.MAX_TREES_TO_PLANT, string.Format("%d (${0})", new_tree_planting*Simulation.TREE_PLANT_COST)); + sim.tree_planting = new_tree_planting; + + int new_tree_clearing = sim.tree_clearing; + ImGui.SliderInt("Tree Clearing", ref new_tree_clearing, 0, Simulation.MAX_TREES_TO_CLEAR, string.Format("%d (${0})", new_tree_clearing*Simulation.TREE_CLEAR_COST)); + sim.tree_clearing = new_tree_clearing; + + ImGui.Text(string.Format("Crowded Trees: {0}", sim.crowded_trees )); + ImGui.Text(string.Format("Percent Healthy Trees: {0:F2}", sim.healthy_percent)); + ImGui.Text(string.Format("Average Age of Trees: {0:F2}", sim.average_tree_age)); + ImGui.Text(string.Format("Max Age of Trees: {0:F2}", sim.max_tree_age)); + + if (ImGui.Button("Okay")) + { + show = false; + } + + ImGui.End(); + ImGui.GetStyle().WindowMenuButtonPosition = ImGuiDir.Left; + ImGui.PopStyleVar(3); + ImGui.PopStyleColor(8); + ImGui.PopFont(); + } + } + } +} \ No newline at end of file diff --git a/isometric-park-fna/Utils/MathUtils.cs b/isometric-park-fna/Utils/MathUtils.cs --- a/isometric-park-fna/Utils/MathUtils.cs +++ b/isometric-park-fna/Utils/MathUtils.cs @@ -19,6 +19,22 @@ } + public static int Clamp(int val, int min, int max) + { + if(val > max) + { + return max; + } + else if (val < min) + { + return min; + } + else + { + return val; + } + } + protected float Decrement(float value, float delta) { float magnitude = Math.Abs(value); @@ -43,5 +59,42 @@ } } + + public static System.Collections.Generic.IEnumerable NextNormalEnumerator(Random random, float mean, float variation) + { + + while (true) { + double u1 = random.NextDouble(); + double u2 = random.NextDouble(); + + double z1 = Math.Sqrt(-2 * Math.Log(u1)) * Math.Cos(2 * Math.PI * u2); + double z2 = Math.Sqrt(-2 * Math.Log(u1)) * Math.Sin(2 * Math.PI * u2); + + yield return (variation * z1) + mean; + yield return (variation * z2) + mean; + } + } + + public static Double NextNormal(Random random, float mean, float variation) + { + //Uses Box-Muller to scale the default uniform distribution + double u1 = random.NextDouble(); + double u2 = random.NextDouble(); + + double z1 = Math.Sqrt(-2 * Math.Log(u1)) * Math.Cos(2 * Math.PI * u2); + double z2 = Math.Sqrt(-2 * Math.Log(u1)) * Math.Sin(2 * Math.PI * u2); + + if(random.NextDouble() > 0.5d) { + return (variation * z1) + mean; + } + else { + return (variation * z2) + mean; + } + + + + } + } + } diff --git a/isometric-park-fna/isometric-park-fna.csproj b/isometric-park-fna/isometric-park-fna.csproj --- a/isometric-park-fna/isometric-park-fna.csproj +++ b/isometric-park-fna/isometric-park-fna.csproj @@ -41,12 +41,14 @@ - - + + + +