using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Media; using System; using System.IO; using System.Reflection; using System.Diagnostics; using System.Collections.Generic; using System.Linq; using SpriteFontPlus; using isometricparkfna; using static isometricparkfna.CellMap; using isometricparkfna.Utils; using isometricparkfna.UI; using isometricparkfna.Engines; using isometricparkfna.Components; using isometricparkfna.Renderers; using isometricparkfna.Messages; using isometricparkfna.Spawners; using Num = System.Numerics; using ImGuiNET.SampleProgram.XNA; using ImGuiNET; using ImPlotNET; using TraceryNet; using Encompass; using Ink.Runtime; //Let's let core builds be deterministic #if NETCOREAPP [assembly:AssemblyVersion("0.36.31.0")] #else [assembly:AssemblyVersion("0.36.31.*")] #endif class FNAGame : Game { private KeyboardState keyboardPrev = new KeyboardState(); private MouseState mousePrev = new MouseState(); private SpriteBatch batch; private SpriteBatch tileBatch; #if DEBUG private SoundEffect sound; #endif private SpriteFont monoFont; private SpriteFont largeMonoFont; private Camera camera = new Camera(new float[] {0.125f, 0.25f, 0.5f, 1.0f, 2.0f, 4.0f }); Random random_generator = new Random(); int frameRate = 0; int frameCounter = 0; TimeSpan elapsedTime = TimeSpan.Zero; TimeSpan drawTime = TimeSpan.Zero; TimeSpan tileDrawTime = TimeSpan.Zero; TimeSpan gridDrawTime = TimeSpan.Zero; TimeSpan treeDrawTime = TimeSpan.Zero; TimeSpan updateTime = TimeSpan.Zero; Queue past_fps = new Queue(100); Queue past_draw = new Queue(100); int tilesDrawn = 0; private static int width = 1280; private static int height = 640; //new tile stuff int squaresAcross = 200; int squaresDown = 200; Simulation simulation; public Vector2 mouseGrid; Vector2 original_point; //for now public bool in_zone; public bool in_active_zone; public bool in_preserve; public bool isPlaying = false; private ImGuiRenderer _imGuiRenderer; private DebugWindow debugWindow; public ImGuiImageMap imageMap; public ImGuiImageMap portraitsMap; public bool show_another_window; public Story Story; //buggy private static bool enableCulling = false; private List newsItems; public bool showGrid; public bool showTrees; private Grammar grammar; private string output; private GraphicsDeviceManager gdm; public bool showBudget; private BudgetWindow budgetWindow; //Encompass private WorldBuilder WorldBuilder = new WorldBuilder(); private World World; private ImGuiWindowBridgeEngine imGuiWindowBridgeEngine; public bool quit = false; private static void Main(string[] args) { #if NETCOREAPP DllMap.Initialise(false); #endif try { using FNAGame g = new FNAGame(); g.Run(); } catch (Exception e) { Logging.Critical(string.Format("Unhandled exception: {0}", e)); return; } #if !DEBUG Logging.logFile.Close(); File.Delete(Logging.logFileName); #endif } private FNAGame() { #if DEBUG foreach (System.Reflection.Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { Logging.Debug("Loaded: " + assembly.ToString() + "\n"); } ; #endif this.gdm = new GraphicsDeviceManager(this) { // Typically you would load a config here... PreferredBackBufferWidth = width, PreferredBackBufferHeight = height, IsFullScreen = false, SynchronizeWithVerticalRetrace = true }; IsFixedTimeStep = false; this.simulation = new Simulation(this.squaresAcross, this.squaresDown, new float[] {16.66667f*240, 16.66667f*120, 16.66667f*60, 16.66667f*30, 16.66667f*1 }); showBudget = false; showGrid = true; showTrees = true; this.Window.Title = "Isometric Park"; Content.RootDirectory = "Content"; } protected override void Initialize() { /* This is a nice place to start up the engine, after * loading configuration stuff in the constructor */ this.IsMouseVisible = true; _imGuiRenderer = new ImGuiRenderer(this); _imGuiRenderer.RebuildFontAtlas(); // Required so fonts are available for rendering base.Initialize(); } protected override void LoadContent() { // Create the batch... this.batch = new SpriteBatch(GraphicsDevice); this.tileBatch = new SpriteBatch(GraphicsDevice); #if DEBUG sound = Content.Load("FNASound"); #endif // Tile.TileSetTexture = Content.Load(@"part4_tileset"); Tile.TileSetTexture = Content.Load(@"merged_tileset"); var texture = Content.Load(@"solid_tileset"); var imageMapTexture = Content.Load(@"photos_converted3"); this.imageMap = new ImGuiImageMap(500, 400, imageMapTexture, _imGuiRenderer, null); var portraitMapTexture = Content.Load(@"portraits"); this.portraitsMap = new ImGuiImageMap(300, 400, portraitMapTexture, _imGuiRenderer, @"Content/portraits.yaml"); Line.initialize(GraphicsDevice); Quad.Initialize(GraphicsDevice, texture); Logging.Success("Initialized Quad texture."); ContractWindow.LoadContent(this._imGuiRenderer, this.imageMap); DialogInterface.LoadContent(this._imGuiRenderer, this.portraitsMap); //Must be done before SetFontMessage is sent var bakedMono = TtfFontBaker.Bake(File.OpenRead(@"Content/iosevka-term-extendedmedium.ttf"), 15, 1024, 1024, new[] { CharacterRange.BasicLatin, CharacterRange.Latin1Supplement, CharacterRange.LatinExtendedA, CharacterRange.Cyrillic, CharacterRange.LatinExtendedB, new CharacterRange((char) 0x00B7) } ); var bakedMonoLarge = TtfFontBaker.Bake(File.OpenRead(@"Content/iosevka-term-extendedmedium.ttf"), 30, 1024, 1024, new[] { CharacterRange.BasicLatin, CharacterRange.Latin1Supplement, CharacterRange.LatinExtendedA, CharacterRange.Cyrillic, CharacterRange.LatinExtendedB, new CharacterRange((char) 0x00B7) } ); monoFont = bakedMono.CreateSpriteFont(GraphicsDevice); largeMonoFont = bakedMonoLarge.CreateSpriteFont(GraphicsDevice); //Has to happen before Encompass stuff, because the Encompass machinery around ImGui requires debugWindow's monoFont to be loaded: this.debugWindow = new DebugWindow(this._imGuiRenderer, GraphicsDevice, this.imageMap); //Has to happen before Encompass stuff, so Spawners can use the grammar: var json2 = new FileInfo(@"Content/grammar.json"); this.grammar = new TraceryNet.Grammar(json2); //Has to happen after Grammar initialization. NewGameWindow.Initialize(this.grammar); this.Story = new Story(File.ReadAllText(@"Content/dialog.json")); //Bindings have to Story.BindExternalFunction ("endGame", () => { Logging.Success("endGame"); this.imGuiWindowBridgeEngine.gameStateMessages.Add(new GameStateMessage {isPlaying = false}); this.imGuiWindowBridgeEngine.typeMessages.Add(new ToggleWindowTypeMessage {Window = isometricparkfna.Messages.Window.MainMenu}); }); Logging.Debug(this.Story.ContinueMaximally()); WorldBuilder.AddEngine(new InputEngine(Menu.MENU_BAR_HEIGHT, this.camera, gdm)); WorldBuilder.AddEngine(new UIEngine(this.Story)); WorldBuilder.AddEngine(new DialogEngine(this.Story, this.grammar)); WorldBuilder.AddEngine(new EventEngine()); var gameBridgeEngine = new GameBridgeEngine(this); WorldBuilder.AddEngine(gameBridgeEngine); WorldBuilder.AddEngine(new GameStateEngine()); WorldBuilder.AddEngine(this.simulation.BridgeEngine); WorldBuilder.AddEngine(new CameraBridgeEngine(this.camera)); this.imGuiWindowBridgeEngine = new ImGuiWindowBridgeEngine(this.debugWindow, debugWindow.monoFont, debugWindow.italicFont, this.simulation); WorldBuilder.AddEngine(this.imGuiWindowBridgeEngine); WorldBuilder.AddEngine(new ContractStatusEngine(this.simulation)); WorldBuilder.AddEngine(new ContractSpawner(simulation.map.MapWidth, simulation.map.MapHeight, this.simulation, this.grammar)); WorldBuilder.AddEngine(new GameSpawner(this.simulation, this, this.grammar)); WorldBuilder.AddEngine(new OrganizationSpawner(this.simulation, this.grammar)); WorldBuilder.AddEngine(new DialogSpawner(this.Story, this.grammar)); WorldBuilder.AddEngine(new PolicyEngine()); WorldBuilder.AddEngine(new TraceryBridgeEngine(this.grammar)); WorldBuilder.AddEngine(new SimulationGameRateBridgeEngine(this.simulation)); WorldBuilder.AddEngine(new BuildToolEngine(this.simulation.map)); WorldBuilder.AddGeneralRenderer(new AreaRenderer(this.tileBatch, this.monoFont), 1); WorldBuilder.AddGeneralRenderer(new ImGuiWindowRenderer(this, this.simulation, this.imGuiWindowBridgeEngine, this.gdm), 2); var contractWindow = WorldBuilder.CreateEntity(); WorldBuilder.SetComponent(contractWindow, new VisibilityComponent { visible = false }); WorldBuilder.SetComponent(contractWindow, new WindowTypeComponent { type = isometricparkfna.Messages.Window.Contracts }); var forestWindow = WorldBuilder.CreateEntity(); WorldBuilder.SetComponent(forestWindow, new VisibilityComponent { visible = false }); WorldBuilder.SetComponent(forestWindow, new WindowTypeComponent { type = isometricparkfna.Messages.Window.Forest }); var newsWindow = WorldBuilder.CreateEntity(); WorldBuilder.SetComponent(newsWindow, new VisibilityComponent { visible = false }); WorldBuilder.SetComponent(newsWindow, new WindowTypeComponent { type = isometricparkfna.Messages.Window.News }); var mainMenu = WorldBuilder.CreateEntity(); WorldBuilder.SetComponent(mainMenu, new VisibilityComponent { visible = true }); WorldBuilder.SetComponent(mainMenu, new WindowTypeComponent { type = isometricparkfna.Messages.Window.MainMenu }); var inputMenu = WorldBuilder.CreateEntity(); WorldBuilder.SetComponent(inputMenu, new VisibilityComponent { visible = false }); WorldBuilder.SetComponent(inputMenu, new WindowTypeComponent { type = isometricparkfna.Messages.Window.InGameMenu }); var optionsWindow = WorldBuilder.CreateEntity(); WorldBuilder.SetComponent(optionsWindow, new VisibilityComponent { visible = false }); WorldBuilder.SetComponent(optionsWindow, new WindowTypeComponent { type = isometricparkfna.Messages.Window.Options }); var newGameWindow = WorldBuilder.CreateEntity(); WorldBuilder.SetComponent(newGameWindow, new VisibilityComponent { visible = false }); WorldBuilder.SetComponent(newGameWindow, new WindowTypeComponent { type = isometricparkfna.Messages.Window.NewGame }); var graphWindow = WorldBuilder.CreateEntity(); WorldBuilder.SetComponent(graphWindow, new VisibilityComponent { visible = false }); WorldBuilder.SetComponent(graphWindow, new WindowTypeComponent { type = isometricparkfna.Messages.Window.Graph }); var preserveTool = WorldBuilder.CreateEntity(); WorldBuilder.SetComponent(preserveTool, new ToolComponent { Tool = Tool.Preserve }); WorldBuilder.SetComponent(preserveTool, new SelectedComponent {Type = SelectionType.Tool, selected = true}); var dezoneTool = WorldBuilder.CreateEntity(); WorldBuilder.SetComponent(dezoneTool, new ToolComponent { Tool = Tool.Dezone }); WorldBuilder.SetComponent(dezoneTool, new SelectedComponent {Type = SelectionType.Tool, selected = false}); var gameEntity = WorldBuilder.CreateEntity(); WorldBuilder.SetComponent(gameEntity, new GameStateComponent { isPlaying = false}); var policyEntity = WorldBuilder.CreateEntity(); WorldBuilder.SetComponent(policyEntity, new TrespassingPolicyComponent { tresspassingPolicy = EnforcementLevel.NoEnforcement}); WorldBuilder.SetComponent(policyEntity, new BudgetLineComponent { }); try { var options = Options.readOptions(); this.imGuiWindowBridgeEngine.fontMessages.Add(new SetFontMessage { fontSize = options.fontSize, fontName = options.fontName }); WorldBuilder.SetComponent(gameEntity, new OptionsComponent {ProfanitySetting = options.profanitySetting}); OptionsWindow.Initialize(new Vector2(FNAGame.width, FNAGame.height), gdm.IsFullScreen, options.profanitySetting); Logging.Success("Loaded options."); } catch (FileNotFoundException e) { Logging.Error(String.Format("Error loading file: {0}", e.ToString())); } World = WorldBuilder.Build(); this.output = grammar.Flatten("#greeting#"); var result = grammar.Flatten("#[assistantName:#assistantNames#][friendOfThePark:#assistantNames#][whatever:whatever]vars#"); Func toUpper = delegate (string i) { return i.ToUpper(); }; grammar.AddModifier("toUpper", toUpper); var newItems = new[] {new NewsItem{hed="Test", contents="#city.toUpper# - This is where the lede would go. #whatever#", source="Wire"} }; this.newsItems = newItems.ToList(); using (var sr = new StreamReader(@"Content/news_items.yaml")) { this.newsItems.AddRange(NewsItem.FromYaml(sr.ReadToEnd())); } using (var sr_pregenerated = new StreamReader(@"Content/news_items_pregenerated.yaml")) { this.newsItems.AddRange(NewsItem.FromYaml(sr_pregenerated.ReadToEnd())); } this.simulation.LoadContent(this.newsItems, this.grammar); this.budgetWindow = new BudgetWindow(new Budget { }, this.monoFont, 0, 0); Logging.Success("Content loaded."); } public void setFont(string font, int size) { var font_path = DebugWindow.fonts[font]; var baked = TtfFontBaker.Bake(File.OpenRead(font_path), size, 1024, 1024, new[] { CharacterRange.BasicLatin, CharacterRange.Latin1Supplement, CharacterRange.LatinExtendedA, CharacterRange.Cyrillic, CharacterRange.LatinExtendedB, new CharacterRange((char) 0x00B7) } ); this.monoFont = baked.CreateSpriteFont(GraphicsDevice); } protected override void UnloadContent() { batch.Dispose(); #if DEBUG sound.Dispose(); #endif Tile.TileSetTexture.Dispose(); Logging.Success("Disposed of Tile texture."); if (Quad.PixelTexture != null) { Quad.PixelTexture.Dispose(); Logging.Success("Disposed of Pixel texture."); } if (Quad.SolidTexture != null) { Quad.SolidTexture.Dispose(); } } Vector2 calculateMousegrid(Vector2 normalizedMousePos) { Vector2 adjust = new Vector2(Tile.TileSpriteWidth / 2, Tile.TileSpriteHeight); Vector2 adjustedMousePos = normalizedMousePos - adjust; float boardx = ((adjustedMousePos.X / Tile.TileSpriteWidth) + (adjustedMousePos.Y / Tile.TileSpriteHeight)); float boardy = ((adjustedMousePos.Y / Tile.TileSpriteHeight) - (adjustedMousePos.X / Tile.TileSpriteWidth)); return new Vector2((int)boardx, (int)boardy); } private String CurrentStatus() { if (this.in_active_zone) { return "Contracted"; } else if (this.in_zone) { return "Proposed Contract"; } else if (this.in_preserve) { return "Preserve"; } else { return "Unused"; } } protected override void Update(GameTime gameTime) { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); #if DEBUG float volume = 1.0f; float pitch = 0.0f; float pan = 0.0f; #endif KeyboardState keyboardCur = Keyboard.GetState(); MouseState mouseCur = Mouse.GetState(); #region input #region misc_keys #if DEBUG if (keyboardCur.IsKeyDown(Keys.OemBackslash) && keyboardPrev.IsKeyUp(Keys.OemBackslash) && keyboardCur.IsKeyDown(Keys.LeftShift)) { sound.Play(volume, pitch, pan); } #endif #endregion misc_keys #endregion input World.Update(gameTime.ElapsedGameTime.TotalSeconds); this.simulation.update(gameTime.ElapsedGameTime); if (this.showBudget) { this.showBudget = this.budgetWindow.update(mouseCur, this.simulation.latestBudget, this.simulation.previousBudget); } this.original_point = Vector2.Transform(new Vector2(mouseCur.X, mouseCur.Y), Matrix.Invert(camera.get_transformation(GraphicsDevice))); this.mouseGrid = this.calculateMousegrid(this.original_point); elapsedTime += gameTime.ElapsedGameTime; if (elapsedTime > TimeSpan.FromSeconds(1)) { elapsedTime -= TimeSpan.FromSeconds(1); frameRate = frameCounter; frameCounter = 0; } this.keyboardPrev = keyboardCur; this.mousePrev = mouseCur; stopWatch.Stop(); this.updateTime = stopWatch.Elapsed; base.Update(gameTime); if (quit) { this.Exit(); } } protected float calculateDepth() { return ((this.squaresAcross + 1) + ((this.squaresDown + 1) * Tile.TileWidth)) * 10; } protected Boolean cull(int gridX, int gridY) { int screenX = (gridX - gridY) * Tile.TileSpriteWidth / 2; int screenY = (gridX + gridY) * Tile.TileSpriteHeight / 2; Vector2 original = Vector2.Transform(new Vector2(screenX, screenY), camera.get_transformation(GraphicsDevice)); return (!FNAGame.enableCulling || (MathUtils.BetweenExclusive(original.X, -Tile.TileSpriteWidth, FNAGame.width) && MathUtils.BetweenExclusive(original.Y, -Tile.TileSpriteHeight, FNAGame.height))); } //Convenience method I'm not super sure about anymore. protected void drawTileAt(int x, int y, int tileIndex, int height) { float maxdepth = ((this.squaresAcross + 1) + ((this.squaresDown + 1) * Tile.TileWidth)) * 10; float depthOffset = 0.7f - ((x + (y * Tile.TileWidth)) / maxdepth); Tile.drawTileAt(this.tileBatch, x, y, tileIndex, height, depthOffset); } protected override void Draw(GameTime gameTime) { frameCounter++; string fps = string.Format("fps: {0}", frameRate); bool has_tree = false; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); GraphicsDevice.Clear(Color.CornflowerBlue); _imGuiRenderer.BeforeLayout(gameTime); if (this.isPlaying) { batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null, camera.get_transformation(GraphicsDevice)); #region draw_tiles Stopwatch stopWatch2 = new Stopwatch(); stopWatch2.Start(); //reset this.tilesDrawn = 0; var scale_factor = 1; var x_adjust = scale_factor > 1 ? -scale_factor : 0; var y_adjust = scale_factor > 1 ? -scale_factor/2 : 0; for (int y = y_adjust; y < this.squaresDown + y_adjust; y += scale_factor) { for (int x = x_adjust; x < this.squaresAcross + x_adjust; x += scale_factor) { int screenx = (x - y) * (Tile.TileSpriteWidth) / 2 - 3*scale_factor; int screeny = (x + y) * (Tile.TileSpriteHeight) / 2; // if (this.cull(x, y)) // { batch.Draw( Tile.TileSetTexture, new Rectangle( screenx, screeny, Tile.TileWidth * scale_factor, Tile.TileHeight * scale_factor), Tile.GetSourceRectangle(1), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.9f); this.tilesDrawn++; // } } } batch.End(); stopWatch2.Stop(); this.tileDrawTime = stopWatch2.Elapsed; #endregion draw_tiles #region draw_gridlines batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null, camera.get_transformation(GraphicsDevice)); stopWatch2 = new Stopwatch(); stopWatch2.Start(); if (this.showGrid) { //need to go one extra so gridlines include the far side of the final tile: for (int y = 0; y < (this.squaresDown + 1); y++) { Vector2 adjust = new Vector2(Tile.TileSpriteWidth / 2, Tile.TileSpriteHeight); //TODO figure out why this second value shouldn't be halved Line.drawLine(batch, new Vector2(((0 - y) * Tile.TileSpriteWidth / 2), (0 + y) * Tile.TileSpriteHeight / 2) + adjust, //new Vector2(this.squaresAcross * Tile.TileSpriteWidth, (y+1) * Tile.TileSpriteHeight), new Vector2((this.squaresAcross - (y)) * Tile.TileSpriteWidth / 2, (this.squaresAcross + (y)) * Tile.TileSpriteHeight / 2) + adjust, Color.White, 0.81f);//Just below the highlighted square and areas } for (int x = 0; x < (this.squaresAcross + 1); x++) { Vector2 adjust = new Vector2(Tile.TileSpriteWidth / 2, Tile.TileSpriteHeight); //TODO figure out why this second value shouldn't be halved Line.drawLine(batch, new Vector2(((x - 0) * Tile.TileSpriteWidth / 2), (x + 0) * Tile.TileSpriteHeight / 2) + adjust, //new Vector2(this.squaresAcross * Tile.TileSpriteWidth, (y+1) * Tile.TileSpriteHeight), new Vector2((x - this.squaresDown) * Tile.TileSpriteWidth / 2, (x + this.squaresDown) * Tile.TileSpriteHeight / 2) + adjust, Color.White, 0.81f); } } batch.End(); stopWatch2.Stop(); this.gridDrawTime = stopWatch2.Elapsed; #endregion draw_gridlines //Gridlines //Lines going down and to the right: /* for (int x = (int)(-this.squaresAcross/2); x < this.squaresAcross; x++) { int rowOffset = 0; float startX = (x * Tile.TileStepX) + baseOffsetX - (Tile.TileStepX / 2); Vector2 start = new Vector2(startX, -baseOffsetY+4); Vector2 stop = new Vector2(startX + this.squaresAcross* Tile.TileStepX/2, this.squaresDown*Tile.TileStepY- baseOffsetY+4); Line.drawLine(batch, Line.departurePoint(stop, start, this.squaresAcross * Tile.TileWidth, this.squaresDown * Tile.TileHeight), Line.departurePoint(start, stop, this.squaresAcross * Tile.TileWidth, this.squaresDown * Tile.TileHeight), Color.White, 0.8f); } //Lines going down and to the left: for (int x = 0; x < (int)(1.5*this.squaresAcross); x++) { float startX = (x * Tile.TileStepX) + baseOffsetX - (Tile.TileStepX / 2); Vector2 start_reverse = new Vector2(startX, -baseOffsetY + 4); Vector2 stop_reverse = new Vector2(startX + -(this.squaresAcross * Tile.TileStepX / 2), (this.squaresDown * Tile.TileStepY) - baseOffsetY + 4); Line.drawLine(batch, Line.departurePoint(stop_reverse, start_reverse, this.squaresAcross * Tile.TileWidth, this.squaresDown * Tile.TileHeight), Line.departurePoint(start_reverse, stop_reverse, this.squaresAcross * Tile.TileWidth, this.squaresDown * Tile.TileHeight), Color.White, 0.8f); } */ tileBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null, camera.get_transformation(GraphicsDevice)); #if DEBUG drawTileAt(4, 4, 140, 3); drawTileAt(6, 4, 141, 3); drawTileAt(8, 4, 142, 2); drawTileAt(10, 4, 142, 3); #endif #region draw_cursor if (MathUtils.Between(this.mouseGrid.X, 0, this.simulation.map.MapWidth) && MathUtils.Between(this.mouseGrid.Y, 0, this.simulation.map.MapHeight)) { Tile.OutlineSquare(tileBatch, this.mouseGrid.X, this.mouseGrid.Y, Color.Yellow, 1); } #if DEBUG Tile.OutlineSquare(tileBatch, 1, 1, Color.Red, 2); Tile.OutlineSquare(tileBatch, 3, 1, Color.Blue, 2); Tile.OutlineSquare(tileBatch, 5, 1, Color.Green, 2); Tile.OutlineSquare(tileBatch, 7, 1, Color.Orange, 2); Tile.OutlineSquare(tileBatch, 9, 1, Color.Orange, 3); //donut Tile.DrawOutlinedSquares(tileBatch, new Vector2[] {new Vector2(19, 1), new Vector2(19, 2), new Vector2(20, 1), new Vector2(21, 1), new Vector2(21, 2), new Vector2(19, 3), new Vector2(20, 3), new Vector2(21, 3) }, Color.Purple); Quad.FillSquare2(tileBatch, 7, 4, Color.Orange, 1.0f, 0.79f); Quad.FillSquare2(tileBatch, 7, 3, Color.Yellow, 1.0f, 0.79f); Quad.FillSquare2(tileBatch, 7, 5, Color.Yellow, .5f, 0.79f); Quad.FillSquare2(tileBatch, 7, 6, Color.Yellow, .25f, 0.79f); Quad.FillSquare2(tileBatch, 7, 7, Color.Yellow, .125f, 0.79f); Quad.FillSquare2(tileBatch, 8, 5, Color.Teal, .5f, 0.79f); Quad.FillSquare2(tileBatch, 8, 6, Color.Teal, .25f, 0.79f); Quad.FillSquare2(tileBatch, 8, 7, Color.Teal, .125f, 0.79f); #endif #endregion draw_cursor stopWatch2 = new Stopwatch(); stopWatch2.Start(); #region draw_trees if (this.showTrees) { for (int i = 0; i < this.simulation.map.MapHeight; i++) { for (int j = 0; j < this.simulation.map.MapWidth; j += 1) { if (this.simulation.map.cells[i][j].HasTree) { //until we actually simulate: if (this.simulation.map.cells[i][j].Type == TreeType.GenericDeciduous) { drawTileAt(i, j, 252, 2); // 142, , 262 } else if (this.simulation.map.cells[i][j].Type == TreeType.Oak) { drawTileAt(i, j, 142, 2); } else if (this.simulation.map.cells[i][j].Type == TreeType.GenericShrub) { drawTileAt(i, j, 210, 2); } else { drawTileAt(i, j, 122, 2); //122, 203, 221 } // 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); // System.Console.WriteLine(String.Format("Drew Dead Tree at {0},{1}", i, j)); } } } } stopWatch2.Stop(); this.treeDrawTime = stopWatch2.Elapsed; #endregion draw_trees #if DEBUG drawTileAt(2, 2, 140, 2); drawTileAt(1, 1, 140, 2); drawTileAt(3, 2, 140, 2); #endif World.Draw(); // _imGuiRenderer.AfterLayout(); tileBatch.End(); #region draw_header batch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null); if (MathUtils.BetweenExclusive(this.mouseGrid.X, 0, this.squaresAcross) && MathUtils.BetweenExclusive(this.mouseGrid.Y, 0, this.squaresAcross)) { has_tree = this.simulation.map.cells[(int)this.mouseGrid.X][(int)this.mouseGrid.Y].HasTree; } String status_left = ""; if (MathUtils.BetweenExclusive(this.mouseGrid.X, -1, this.simulation.map.MapWidth) && MathUtils.BetweenExclusive(this.mouseGrid.Y, -1, this.simulation.map.MapHeight)) { var treeStatus = this.simulation.map.cells[(int)this.mouseGrid.X][(int)this.mouseGrid.Y].Status; var treeStatusAdjective = this.simulation.map.cells[(int)this.mouseGrid.X][(int)this.mouseGrid.Y].StatusAdjective; var treeType = this.simulation.map.cells[(int)this.mouseGrid.X][(int)this.mouseGrid.Y].TypeName; var useStatus = this.CurrentStatus(); if (treeStatus != CellStatus.Clear) { status_left = String.Format("{0:},{1:} {2} {3} ({4})", this.mouseGrid.X, this.mouseGrid.Y, treeStatusAdjective, treeType, useStatus); } else { status_left = String.Format("{0:},{1:} {2} ({3})", this.mouseGrid.X, this.mouseGrid.Y, treeStatusAdjective, useStatus); } } String header_left = String.Format("${0:}|{1:} \ue124", this.simulation.money, this.simulation.map.tree_count); String header_middle = String.Format("{0:MMMMM yyyy} ({1:})", this.simulation.DateTime, this.simulation.Season); // String header_right = String.Format("Press H for help."); String header_right = ""; this.Window.Title = String.Format("Isometric Park [{0:}]", header_middle); Vector2 middle_dimensions = monoFont.MeasureString(header_middle); Vector2 right_dimensions = monoFont.MeasureString(header_right); float middle_start = (int)((FNAGame.width / 2) - (middle_dimensions.X / 2)); float right_start = (int)(FNAGame.width - right_dimensions.X - 10.0f); float top = (float)Math.Round(FNAGame.height - middle_dimensions.Y); // Rounding so the int and float versions are closer. FilledRectangle.drawFilledRectangle(batch, new Rectangle(0, (int)top, width, (int)middle_dimensions.Y), Color.White, 0.51f); batch.DrawString(monoFont, status_left, new Vector2(1, top), Color.Black, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.5f); 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 #region budget if (this.showBudget) { budgetWindow.draw(batch); } #endregion budget batch.End(); #region window Menu.Render(debugWindow.monoFont, FNAGame.width, this.imGuiWindowBridgeEngine, ref quit, ref this.simulation.paused, ref this.simulation.currentRate, ref this.showBudget, header_left); if (quit) { System.Environment.Exit(0); } } else { GraphicsDevice.Clear(Color.Teal); batch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null); Vector2 middle_dimensions = largeMonoFont.MeasureString("Isometric Park"); float middle_start = (int)((FNAGame.width / 2) - (middle_dimensions.X / 2)); batch.DrawString(largeMonoFont, "Isometric Park", new Vector2(middle_start, 50), Color.Black, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.5f); batch.DrawString(largeMonoFont, "Isometric Park", new Vector2(middle_start-1, 49), Color.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.51f); World.Draw(); Vector2 version_dimensions = monoFont.MeasureString(typeof(FNAGame).Assembly.GetName().Version.ToString()); batch.DrawString(monoFont, typeof(FNAGame).Assembly.GetName().Version.ToString(), new Vector2(0, FNAGame.height-version_dimensions.Y), Color.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.51f); Vector2 name_dimensions = monoFont.MeasureString("by actuallyalys<3"); float name_start = (int)(FNAGame.width / 2) - (name_dimensions.X / 2); batch.DrawString(monoFont, "by actuallyalys <3", new Vector2(name_start, 50+middle_dimensions.Y), Color.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.51f); batch.End(); } #endregion #region debug_window //Calcs for debug window: past_draw.Enqueue(this.drawTime); if ((this.frameCounter % 15) == 0) { past_fps.Enqueue(this.frameRate); /* if (this.frameRate > 60.0) { Logging.Warning(String.Format("Framerate is higher than limit: {0}", this.frameRate)); } if (this.frameRate < 30.0) { Logging.Warning(String.Format("Framerate is lower than desired: {0}", this.frameRate)); } */ } /* if (this.frameRate > 120.0) { Logging.Error(String.Format("Framerate is much higher than limit: {0}", this.frameRate)); } else if (this.frameRate < 15.0) { Logging.Error(String.Format("Framerate is much lower than desired: {0}", this.frameRate)); } */ DebugInfo debugInfo = new DebugInfo { fps = this.frameRate, pastFps = past_fps.ToArray(), cameraPosition = camera.position, drawTime = this.drawTime, treeDrawTime = this.treeDrawTime, gridDrawTime = this.gridDrawTime, tileDrawTime = this.tileDrawTime, updateTime = this.updateTime, treeCount = this.simulation.map.tree_count, mouseGrid = this.mouseGrid, hasTree = has_tree, tilesDrawn = this.tilesDrawn }; //Finally, draw the debug window var additionalInfo = new Dictionary(); Vector2 cameraMiddle = this.camera.position + new Vector2(FNAGame.width / 2, FNAGame.height / 2); var state = Mouse.GetState(); Vector2 delta = this.camera.position - this.original_point; additionalInfo.Add("cameraMiddle", cameraMiddle.ToString()); additionalInfo.Add("mouse ", String.Format("{0}, {1}", state.X, state.Y)); additionalInfo.Add("mouse delta", delta.ToString()); string entries = ""; string descriptions = ""; foreach (var pair in DialogSpawner.indexes) { entries += String.Format("{0}={1},", pair.Key, pair.Value); } foreach (var meta in portraitsMap.Metadata) { descriptions += String.Format("{0}: {1}\n", meta.Filename, meta.Description); } additionalInfo.Add("Tracery Test", this.output); additionalInfo.Add("Log Entry", string.Format("{0} {1}", Logging.entries[Logging.entries.Count-1].level, Logging.entries[Logging.entries.Count-1].message)); additionalInfo.Add("Dialog entries", entries); additionalInfo.Add("Metadata entries", descriptions); if (past_fps.Count() > 5) { additionalInfo.Add(".01%% fps", MathUtils.Percentile(past_fps.Skip(5).ToArray(), 0.0001f).ToString()); additionalInfo.Add(".1%% fps", MathUtils.Percentile(past_fps.Skip(5).ToArray(), 0.001f).ToString()); additionalInfo.Add("1%% fps", MathUtils.Percentile(past_fps.Skip(5).ToArray(), 0.01f).ToString()); additionalInfo.Add("50%% fps", MathUtils.Percentile(past_fps.Skip(5).ToArray(), 0.50f).ToString()); } if (past_draw.Count() > 5) { var past_draw_floats = past_draw.Skip(5).Select(ts => ts.TotalMilliseconds).ToArray(); additionalInfo.Add(".01%% draw", MathUtils.Percentile(past_draw_floats, 0.0001f).ToString()); additionalInfo.Add(".1%% draw", MathUtils.Percentile(past_draw_floats, 0.001f).ToString()); additionalInfo.Add("1%% draw", MathUtils.Percentile(past_draw_floats, 0.01f).ToString()); additionalInfo.Add("50%% draw", MathUtils.Percentile(past_draw_floats, 0.50f).ToString()); additionalInfo.Add("99%% draw", MathUtils.Percentile(past_draw_floats, 0.99f).ToString()); additionalInfo.Add("99.9%% draw", MathUtils.Percentile(past_draw_floats, 0.999f).ToString()); additionalInfo.Add("99.99%% draw", MathUtils.Percentile(past_draw_floats, 0.9999f).ToString()); } debugWindow.Layout(debugInfo, additionalInfo, ref show_another_window); _imGuiRenderer.AfterLayout(); #endregion debug_window stopWatch.Stop(); this.drawTime = stopWatch.Elapsed; base.Draw(gameTime); } public void setResolution(Vector2 newResolution, bool fullscreen) { FNAGame.width = (int)newResolution.X; FNAGame.height = (int)newResolution.Y; this.gdm.PreferredBackBufferWidth = (int)newResolution.X; this.gdm.PreferredBackBufferHeight = (int)newResolution.Y; this.gdm.IsFullScreen = fullscreen; this.gdm.ApplyChanges(); } }