├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── Contracts ├── Contracts.csproj ├── Faction.cs └── TileData.cs ├── Engine ├── ActorManager.cs ├── CaveMapCreationStrategy.cs ├── CelluarAutomataTests.cs ├── CellularAutomata.cs ├── Engine.cs ├── Engine.csproj ├── EngineConstants.cs ├── EngineLogger.cs ├── Filters.cs └── PlayerInput.cs ├── EntityComponentSystemCSharp ├── Components.cs ├── DuplicateComponentException.cs ├── EntityComponentSystemCSharp.csproj ├── EntityExtensions.cs ├── EntityManager.cs ├── MissingComponentException.cs ├── NotComponentException.cs ├── Orientation.cs ├── PointWrapper.cs ├── Systems │ ├── CombatSystem.cs │ ├── DemandSystem.cs │ ├── EnergySystem.cs │ ├── HealthSystem.cs │ ├── IEngine.cs │ ├── ISystem.cs │ ├── MovementSystem.cs │ ├── ProductionSystem.cs │ ├── StackSystem.cs │ ├── SystemBase.cs │ └── WanderingMonsterSystem.cs └── Test │ ├── EntityManagerTests.cs │ ├── EntityPrototypeTests.cs │ ├── MockEngine.cs │ ├── MockLogger.cs │ ├── ProductionTests.MockMap.cs │ └── ProductionTests.cs ├── EntityPrototypes.json ├── FeatureDetector ├── Detector.cs ├── DetectorTests.cs ├── FeatureDetector.csproj └── FeatureFilters.cs ├── InventionHackGameplay.gif ├── InventionUiAndroid ├── InventionUiAndroid.csproj ├── MainActivity.cs ├── Properties │ ├── AndroidManifest.xml │ └── AssemblyInfo.cs └── Resources │ ├── Resource.designer.cs │ ├── layout │ └── activity_main.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── ic_launcher_background.xml │ ├── strings.xml │ └── styles.xml ├── InventionUiUwp ├── App.xaml ├── App.xaml.cs ├── Assets │ ├── LockScreenLogo.scale-200.png │ ├── SplashScreen.scale-200.png │ ├── Square150x150Logo.scale-200.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── StoreLogo.png │ └── Wide310x150Logo.scale-200.png ├── InventionUiUwp.csproj ├── MainPage.xaml ├── MainPage.xaml.cs ├── Package.appxmanifest └── Properties │ ├── AssemblyInfo.cs │ └── Default.rd.xml ├── InventionUiWpf ├── InventionUiWpf.csproj ├── Program.cs └── packages.config ├── InventionUiiOS ├── AppDelegate.cs ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon1024.png │ │ ├── Icon120.png │ │ ├── Icon152.png │ │ ├── Icon167.png │ │ ├── Icon180.png │ │ ├── Icon20.png │ │ ├── Icon29.png │ │ ├── Icon40.png │ │ ├── Icon58.png │ │ ├── Icon60.png │ │ ├── Icon76.png │ │ ├── Icon80.png │ │ └── Icon87.png ├── Entitlements.plist ├── Info.plist ├── InventionUiiOS.csproj ├── LaunchScreen.storyboard ├── Main.cs ├── Properties │ └── AssemblyInfo.cs ├── Resources │ └── LaunchScreen.xib └── SceneDelegate.cs ├── LICENSE ├── MegaDungeon.sln ├── MegaDungeon.sln.Android ├── Portable ├── Cloth.cs ├── ColorPallete.cs ├── EntityData.cs ├── MegaDungeonUI.cs ├── MegaDungeonUIConstants.cs ├── Portable.csproj ├── Shell.cs └── TileManager.cs ├── README.md ├── absurd64.bmp ├── nuget.exe ├── runtests.ps1 └── tiledata.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.txt 2 | *nh_progress.dat 3 | **/__pycache__/* 4 | *.mod 5 | **/cache/* 6 | **/*.ttyrec* 7 | **/*.h5 8 | **/*.hf5 9 | **/*.model 10 | **/rundata/* 11 | **/notes/* 12 | 13 | 14 | ## Ignore Visual Studio temporary files, build results, and 15 | ## files generated by popular Visual Studio add-ons. 16 | ## 17 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 18 | 19 | # User-specific files 20 | *.rsuser 21 | *.suo 22 | *.user 23 | *.userosscache 24 | *.sln.docstates 25 | 26 | #PerfView Traces 27 | PerfViewData.etl.zip 28 | 29 | # User-specific files (MonoDevelop/Xamarin Studio) 30 | *.userprefs 31 | 32 | # Build results 33 | [Dd]ebug/ 34 | [Dd]ebugPublic/ 35 | [Rr]elease/ 36 | [Rr]eleases/ 37 | x64/ 38 | x86/ 39 | [Aa][Rr][Mm]/ 40 | [Aa][Rr][Mm]64/ 41 | bld/ 42 | [Bb]in/ 43 | [Oo]bj/ 44 | [Ll]og/ 45 | 46 | # Visual Studio 2015/2017 cache/options directory 47 | .vs/ 48 | # Uncomment if you have tasks that create the project's static files in wwwroot 49 | #wwwroot/ 50 | 51 | # Visual Studio 2017 auto generated files 52 | Generated\ Files/ 53 | 54 | # MSTest test Results 55 | [Tt]est[Rr]esult*/ 56 | [Bb]uild[Ll]og.* 57 | 58 | # NUNIT 59 | *.VisualState.xml 60 | TestResult.xml 61 | 62 | # Build Results of an ATL Project 63 | [Dd]ebugPS/ 64 | [Rr]eleasePS/ 65 | dlldata.c 66 | 67 | # Benchmark Results 68 | BenchmarkDotNet.Artifacts/ 69 | 70 | # .NET Core 71 | project.lock.json 72 | project.fragment.lock.json 73 | artifacts/ 74 | 75 | # StyleCop 76 | StyleCopReport.xml 77 | 78 | # Files built by Visual Studio 79 | *_i.c 80 | *_p.c 81 | *_h.h 82 | *.ilk 83 | *.meta 84 | *.obj 85 | *.iobj 86 | *.pch 87 | *.pdb 88 | *.ipdb 89 | *.pgc 90 | *.pgd 91 | *.rsp 92 | *.sbr 93 | *.tlb 94 | *.tli 95 | *.tlh 96 | *.tmp 97 | *.tmp_proj 98 | *_wpftmp.csproj 99 | *.log 100 | *.vspscc 101 | *.vssscc 102 | .builds 103 | *.pidb 104 | *.svclog 105 | *.scc 106 | 107 | # Chutzpah Test files 108 | _Chutzpah* 109 | 110 | # Visual C++ cache files 111 | ipch/ 112 | *.aps 113 | *.ncb 114 | *.opendb 115 | *.opensdf 116 | *.sdf 117 | *.cachefile 118 | *.VC.db 119 | *.VC.VC.opendb 120 | 121 | # Visual Studio profiler 122 | *.psess 123 | *.vsp 124 | *.vspx 125 | *.sap 126 | 127 | # Visual Studio Trace Files 128 | *.e2e 129 | 130 | # TFS 2012 Local Workspace 131 | $tf/ 132 | 133 | # Guidance Automation Toolkit 134 | *.gpState 135 | 136 | # ReSharper is a .NET coding add-in 137 | _ReSharper*/ 138 | *.[Rr]e[Ss]harper 139 | *.DotSettings.user 140 | 141 | # JustCode is a .NET coding add-in 142 | .JustCode 143 | 144 | # TeamCity is a build add-in 145 | _TeamCity* 146 | 147 | # DotCover is a Code Coverage Tool 148 | *.dotCover 149 | 150 | # AxoCover is a Code Coverage Tool 151 | .axoCover/* 152 | !.axoCover/settings.json 153 | 154 | # Visual Studio code coverage results 155 | *.coverage 156 | *.coveragexml 157 | 158 | # NCrunch 159 | _NCrunch_* 160 | .*crunch*.local.xml 161 | nCrunchTemp_* 162 | 163 | # MightyMoose 164 | *.mm.* 165 | AutoTest.Net/ 166 | 167 | # Web workbench (sass) 168 | .sass-cache/ 169 | 170 | # Installshield output folder 171 | [Ee]xpress/ 172 | 173 | # DocProject is a documentation generator add-in 174 | DocProject/buildhelp/ 175 | DocProject/Help/*.HxT 176 | DocProject/Help/*.HxC 177 | DocProject/Help/*.hhc 178 | DocProject/Help/*.hhk 179 | DocProject/Help/*.hhp 180 | DocProject/Help/Html2 181 | DocProject/Help/html 182 | 183 | # Click-Once directory 184 | publish/ 185 | 186 | # Publish Web Output 187 | *.[Pp]ublish.xml 188 | *.azurePubxml 189 | # Note: Comment the next line if you want to checkin your web deploy settings, 190 | # but database connection strings (with potential passwords) will be unencrypted 191 | *.pubxml 192 | *.publishproj 193 | 194 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 195 | # checkin your Azure Web App publish settings, but sensitive information contained 196 | # in these scripts will be unencrypted 197 | PublishScripts/ 198 | 199 | # NuGet Packages 200 | *.nupkg 201 | # The packages folder can be ignored because of Package Restore 202 | **/[Pp]ackages/* 203 | # except build/, which is used as an MSBuild target. 204 | !**/[Pp]ackages/build/ 205 | # Uncomment if necessary however generally it will be regenerated when needed 206 | #!**/[Pp]ackages/repositories.config 207 | # NuGet v3's project.json files produces more ignorable files 208 | *.nuget.props 209 | *.nuget.targets 210 | 211 | # Microsoft Azure Build Output 212 | csx/ 213 | *.build.csdef 214 | 215 | # Microsoft Azure Emulator 216 | ecf/ 217 | rcf/ 218 | 219 | # Windows Store app package directories and files 220 | AppPackages/ 221 | BundleArtifacts/ 222 | Package.StoreAssociation.xml 223 | _pkginfo.txt 224 | *.appx 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | # ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true 251 | **/wwwroot/lib/ 252 | 253 | # RIA/Silverlight projects 254 | Generated_Code/ 255 | 256 | # Backup & report files from converting an old project file 257 | # to a newer Visual Studio version. Backup files are not needed, 258 | # because we have git ;-) 259 | _UpgradeReport_Files/ 260 | Backup*/ 261 | UpgradeLog*.XML 262 | UpgradeLog*.htm 263 | ServiceFabricBackup/ 264 | *.rptproj.bak 265 | 266 | # SQL Server files 267 | *.mdf 268 | *.ldf 269 | *.ndf 270 | 271 | # Business Intelligence projects 272 | *.rdl.data 273 | *.bim.layout 274 | *.bim_*.settings 275 | *.rptproj.rsuser 276 | *- Backup*.rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # JetBrains Rider 313 | .idea/ 314 | *.sln.iml 315 | 316 | # CodeRush personal settings 317 | .cr/personal 318 | 319 | # Python Tools for Visual Studio (PTVS) 320 | __pycache__/ 321 | *.pyc 322 | 323 | # Cake - Uncomment if you are using it 324 | # tools/** 325 | # !tools/packages.config 326 | 327 | # Tabs Studio 328 | *.tss 329 | 330 | # Telerik's JustMock configuration file 331 | *.jmconfig 332 | 333 | # BizTalk build output 334 | *.btp.cs 335 | *.btm.cs 336 | *.odx.cs 337 | *.xsd.cs 338 | 339 | # OpenCover UI analysis results 340 | OpenCover/ 341 | 342 | # Azure Stream Analytics local run output 343 | ASALocalRun/ 344 | 345 | # MSBuild Binary and Structured Log 346 | *.binlog 347 | 348 | # NVidia Nsight GPU debugger configuration file 349 | *.nvuser 350 | 351 | # MFractors (Xamarin productivity tool) working folder 352 | .mfractor/ 353 | 354 | # Local History for Visual Studio 355 | .localhistory/ 356 | 357 | # BeatPulse healthcheck temp database 358 | healthchecksdb 359 | 360 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 361 | MigrationBackup/ -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": ".NET Launch (console)", 9 | "type": "clr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | "program": "${workspaceFolder}/bin/Debug/InventionUiWpf/net461/InventionUiWpf.exe", 13 | "args": [], 14 | "cwd": "${workspaceFolder}", 15 | "console": "internalConsole", 16 | "stopAtEntry": false 17 | }, 18 | { 19 | "name": ".NET Core Attach", 20 | "type": "coreclr", 21 | "request": "attach", 22 | "processId": "${command:pickProcess}" 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "build", 8 | "command": "dotnet", 9 | "type": "shell", 10 | "args": [ 11 | "build" 12 | ], 13 | "group": { 14 | "kind": "build", 15 | "isDefault": true 16 | }, 17 | "problemMatcher": "$msCompile" 18 | }, 19 | { 20 | "label": "test", 21 | "command": "dotnet", 22 | "type": "shell", 23 | "args": [ 24 | "test" 25 | ], 26 | "group": { 27 | "kind": "test", 28 | "isDefault": true 29 | }, 30 | "problemMatcher": "$msCompile" 31 | } 32 | ] 33 | } -------------------------------------------------------------------------------- /Contracts/Contracts.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard20 5 | $(SolutionDir)\bin\$(Configuration)\$(AssemblyName)\ 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Contracts/Faction.cs: -------------------------------------------------------------------------------- 1 | /* 2 | TileData.json Contract. 3 | */ 4 | 5 | namespace MegaDungeon.Contracts 6 | { 7 | public enum Factions 8 | { 9 | Player, 10 | Neutral, 11 | Monster 12 | } 13 | } -------------------------------------------------------------------------------- /Contracts/TileData.cs: -------------------------------------------------------------------------------- 1 | /* 2 | TileData.json Contract. 3 | */ 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace MegaDungeon.Contracts 8 | { 9 | public class TileData 10 | { 11 | public int tile_size; 12 | public Dictionary data; 13 | 14 | } 15 | 16 | public class TileDataData 17 | { 18 | public string name; 19 | public string type; 20 | } 21 | 22 | public interface ITileManager 23 | { 24 | byte[] GetTileBmpBytes(int index); 25 | int GetGlyphNumByName(string name); 26 | } 27 | } -------------------------------------------------------------------------------- /Engine/ActorManager.cs: -------------------------------------------------------------------------------- 1 | using EntityComponentSystemCSharp; 2 | using EntityComponentSystemCSharp.Components; 3 | using static MegaDungeon.EngineConstants; 4 | 5 | namespace MegaDungeon 6 | { 7 | public class ActorManager 8 | { 9 | EntityManager _entityManager; 10 | public ActorManager(EntityManager entityManager) 11 | { 12 | _entityManager = entityManager; 13 | } 14 | 15 | public EntityManager.Entity GetPlayerActor(int playerGlyph) 16 | { 17 | var actor = CreateActor( 18 | playerGlyph, 19 | name: "Valkerie", 20 | maxHealth: 10, 21 | defense: 10, 22 | power: 10, 23 | accuracy: 75, 24 | speed: 10 25 | ); 26 | actor.AddComponent(new SightStat(){Range=5}); 27 | actor.AddComponent(); 28 | return actor; 29 | } 30 | 31 | public EntityManager.Entity CreateActor(int glyph, string name = "actor", int maxHealth = 1,int defense = 1, int power = 1,int accuracy = 70, float speed = 8.0F) 32 | { 33 | var actor = _entityManager.CreateEntity(); 34 | actor.AddComponent(new Actor(){Gold = 0, Speed = speed}); 35 | actor.AddComponent(new AttackStat(){Accuracy = accuracy, Power = power}); 36 | actor.AddComponent(new DefenseStat(){Chance = defense}); 37 | actor.AddComponent(new Life(){Health = maxHealth, MaxHealth = maxHealth}); 38 | actor.AddComponent(new Name(){NameString = name}); 39 | actor.AddComponent(new Glyph{glyph = glyph}); 40 | return actor; 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Engine/CaveMapCreationStrategy.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using RogueSharp; 3 | using FeatureDetector; 4 | using RogueSharp.MapCreation; 5 | using Engine; 6 | using System; 7 | using RoyT.AStar; 8 | using System.Collections.Generic; 9 | using static FeatureDetector.MapFeatureDetector; 10 | using System.Linq; 11 | 12 | namespace MegaDungeon 13 | { 14 | public class CaveMapCreationStrategy : IMapCreationStrategy where T : IMap, new() 15 | { 16 | Random random = new Random(); 17 | int _width; 18 | int _height; 19 | double _density; 20 | public CaveMapCreationStrategy(int width, int height, double density = 0.50) 21 | { 22 | _width = width; 23 | _height = height; 24 | _density = density; 25 | } 26 | 27 | public T CreateMap() 28 | { 29 | var cave = CellularAutomata.GenerateCaves(_width, _height, _density); 30 | var regionMap = MapFeatureDetector.GetRegions(cave); 31 | 32 | // Pick a random room to start and dig a tunnel to a random other room. 33 | // Go from there to another random room until all are connected. 34 | var roomCenters = GetRoomCenters(regionMap).ToList(); 35 | var startPoint = roomCenters[random.Next(roomCenters.Count)]; 36 | roomCenters.Remove(startPoint); 37 | 38 | while(roomCenters.Count > 0) 39 | { 40 | var nextPoint = roomCenters[random.Next(roomCenters.Count)]; 41 | roomCenters.Remove(nextPoint); 42 | cave = CreatePath(cave, startPoint.X, startPoint.Y, nextPoint.X, nextPoint.Y); 43 | startPoint = nextPoint; 44 | } 45 | var map = new RogueSharp.Map(_width, _height); 46 | foreach(var cell in map.GetAllCells()) 47 | { 48 | var open = cave[cell.X, cell.Y] == 0; 49 | map.SetCellProperties(cell.X, cell.Y, isTransparent: open, isWalkable: open, false); 50 | } 51 | 52 | return (T)(object)map; 53 | } 54 | 55 | private int[,] CreatePath(int[,] map, int x1, int y1, int x2, int y2) 56 | { 57 | int[,] returnMap = (int[,]) map.Clone(); 58 | Grid grid = CreateGrid(map); 59 | var start = new Position(x1, y1); 60 | var end = new Position(x2, y2); 61 | var path = grid.GetPath(start, end, MovementPatterns.LateralOnly); 62 | foreach(var p in path) 63 | { 64 | returnMap[p.X, p.Y] = 0; 65 | } 66 | return returnMap; 67 | } 68 | 69 | private Grid CreateGrid(int[,] cave) 70 | { 71 | var pathfinder = new RoyT.AStar.Grid(_width, _height); 72 | for (int x = 0; x < _width; x++) 73 | { 74 | for (int y = 0; y < _height; y++) 75 | { 76 | pathfinder.SetCellCost(new RoyT.AStar.Position(x, y), (cave[x, y] + 1) * 10); 77 | } 78 | } 79 | 80 | return pathfinder; 81 | } 82 | 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Engine/CelluarAutomataTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using FeatureDetector; 3 | using MegaDungeon; 4 | using System.Diagnostics; 5 | 6 | namespace Engine 7 | { 8 | [TestFixture] 9 | public class CelluarAutomataTests 10 | { 11 | 12 | 13 | [Test] 14 | public void RandomFillTest() 15 | { 16 | var w = 10; 17 | var h = 10; 18 | var total = 0; 19 | for (int i = 0; i < 100; i++) 20 | { 21 | var result = CellularAutomata.RandomFill(h, w); 22 | total += result.Total(); 23 | } 24 | var expected = w * h / 2; 25 | var avg = total / 100; 26 | var epsilon = w * h / 4; 27 | Assert.AreEqual(expected, avg, epsilon); 28 | } 29 | 30 | [Test] 31 | public void ConvoleTest() 32 | { 33 | 34 | var grid = CellularAutomata.RandomFill(10, 15); 35 | var conv = CellularAutomata.Convolve(grid, FeatureFilters.Identity); 36 | var gTotal = grid.Total(); 37 | var cTotal = conv.Total(); 38 | Assert.AreEqual(gTotal, cTotal); 39 | } 40 | 41 | [Test] 42 | public void TimeSteptest() 43 | { 44 | var w = 100; 45 | var h = 150; 46 | var grid = CellularAutomata.RandomFill(w, h, 0.45); 47 | 48 | // caves B678/S345678 49 | int[] born = new[] { 6,7,8 }; 50 | int[] survive = new[] { 3, 4, 5, 6, 7, 8 }; 51 | 52 | for (int i = 0; i < 5; i++) 53 | { 54 | grid = CellularAutomata.RunAutomataTimestep(grid, born, survive); 55 | Debug.WriteLine(grid.ToRowString(asMap: true)); 56 | } 57 | } 58 | 59 | [Test] 60 | public void CaveTest() 61 | { 62 | var strat = new CaveMapCreationStrategy(100, 120, 0.65); 63 | var map = strat.CreateMap(); 64 | Debug.WriteLine(map.ToString()); 65 | } 66 | 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /Engine/CellularAutomata.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using FeatureDetector; 4 | using System.Diagnostics; 5 | 6 | namespace Engine 7 | { 8 | public static class CellularAutomata 9 | { 10 | static Random _rand = new Random(); 11 | 12 | public static int[,] RandomFill(int width, int height, double fill = 0.5F) 13 | { 14 | var grid = new int[width, height]; 15 | grid.UpDate(c => c = (_rand.NextDouble() < fill)? 1 : 0); 16 | return grid; 17 | } 18 | 19 | 20 | public static int[,] Convolve(int[,] grid, int[,] filter) 21 | { 22 | return FeatureDetector.MapFeatureDetector.ConvolveFilter(grid, filter); 23 | } 24 | 25 | public static int[,] RunAutomataTimestep(int[,] grid, int[] born, int[] survive) 26 | { 27 | var newgrid = new int[grid.GetLength(0), grid.GetLength(1)]; 28 | var neighbors = CellularAutomata.Convolve(grid, FeatureFilters.NeighborCount); 29 | Debug.WriteLine(neighbors.Total()); 30 | for (int x = 0; x < grid.GetLength(0); x++) 31 | { 32 | for (int y = 0; y < grid.GetLength(1); y++) 33 | { 34 | if (grid[x, y] == 1 && survive.Contains(neighbors[x, y])) 35 | { 36 | newgrid[x, y] = 1; 37 | } 38 | else if (grid[x, y] == 0 && born.Contains(neighbors[x, y])) 39 | { 40 | newgrid[x, y] = 1; 41 | } 42 | else 43 | { 44 | newgrid[x, y] = 0; 45 | } 46 | } 47 | } 48 | return newgrid; 49 | } 50 | 51 | public static int[,] GenerateCaves(int width, int height, double density = 0.45) 52 | { 53 | // caves B678/S345678 54 | var grid = CellularAutomata.RandomFill(width, height, density); 55 | 56 | int[] born = new[] { 6,7,8 }; 57 | int[] survive = new[] { 3, 4, 5, 6, 7, 8 }; 58 | 59 | for (int i = 0; i < 5; i++) 60 | { 61 | grid = CellularAutomata.RunAutomataTimestep(grid, born, survive); 62 | } 63 | 64 | return grid; 65 | } 66 | 67 | 68 | } 69 | } -------------------------------------------------------------------------------- /Engine/Engine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Diagnostics; 5 | using EntityComponentSystemCSharp; 6 | using EntityComponentSystemCSharp.Components; 7 | using EntityComponentSystemCSharp.Systems; 8 | using RogueSharp; 9 | using FeatureDetector; 10 | using MegaDungeon.Contracts; 11 | using static MegaDungeon.EngineConstants; 12 | using static EntityComponentSystemCSharp.EntityManager; 13 | 14 | namespace MegaDungeon 15 | { 16 | public class Engine : IEngine 17 | { 18 | int _doorPercentChance = 50; // Percentage of possible doors that will actually spawn. 19 | int _messageLimit = 5; 20 | Random random = new Random(); 21 | int _width; 22 | int _height; 23 | int[,] _floor; 24 | int[,] _floor_view; // a copy to return to make _floor effectively readonly 25 | RogueSharp.IMap _map; 26 | ITileManager _tileManager; 27 | Location _playerLocation = new Location(); 28 | List _doorways = new List(); 29 | EntityManager _entityManager = new EntityManager(); 30 | List _spawnLocations = new List(); 31 | List _turnSystems = new List(); 32 | internal Queue _messages = new Queue(); 33 | SightStat _playerSiteDistance; 34 | EntityManager.Entity _player; 35 | ActorManager _actorManager; 36 | HashSet _viewable; 37 | EngineLogger _logger; 38 | List _doors = new List(); 39 | public ISystemLogger GetLogger() {return _logger;} 40 | public RogueSharp.IMap GetMap() {return _map;} 41 | public ITileManager GetTileManager() {return _tileManager;} 42 | public EntityManager GetEntityManager() {return _entityManager;} 43 | public HashSet GetPlayerViewable() {return _viewable;} 44 | public Point GetPlayerLocation() {return new Point(){X = _playerLocation.X, Y = _playerLocation.Y};} 45 | int DIRT, FLOOR, TILEABLEWALL, DARK, DOOR, PLAYER; 46 | 47 | public HashSet Viewable 48 | { 49 | get => _viewable; 50 | } 51 | 52 | public EntityManager.Entity PlayerEntity 53 | { 54 | get => _player; 55 | } 56 | 57 | public Point PlayerLocation 58 | { 59 | get => new Point(_playerLocation.X, _playerLocation.Y); 60 | } 61 | 62 | public string[] Messages 63 | { 64 | get => _messages.ToArray(); 65 | } 66 | 67 | /// 68 | /// A grid of glyphs representing the discovered map. 69 | /// 70 | /// 71 | public int[,] Floor 72 | { 73 | get{ return _floor_view;} 74 | } 75 | 76 | public int[,] RevealedFloor 77 | { 78 | get{ return (int[,])_floor;} 79 | } 80 | 81 | /// 82 | /// Dungeon floor engine, seperate from any UI. 83 | /// 84 | /// 85 | /// 86 | /// 87 | public Engine(int width, int height, ITileManager tileManager) 88 | { 89 | _width = width; 90 | _height = height; 91 | _floor = new int[width, height]; 92 | _tileManager = tileManager; 93 | SetCommonTileGlyphs(); 94 | 95 | // RandomizeCave(); 96 | RandomizeFloor(); 97 | // BigRoom(); 98 | InitCellGlyphs(); 99 | _actorManager = new ActorManager(_entityManager); 100 | InitializePlayer(); 101 | PlaceMonsters(); 102 | UpdateViews(); 103 | 104 | // Add systems that should run every turn here. 105 | _logger = new EngineLogger(this); 106 | 107 | // Setup systems to run. Order matters. 108 | _turnSystems.Add(new CombatSystem(this)); 109 | _turnSystems.Add(new HealthSystem(this)); 110 | _turnSystems.Add(new EnergySystem(this)); 111 | _turnSystems.Add(new WanderingMonsterSystem(this)); 112 | _turnSystems.Add(new MovementSystem(this)); 113 | } 114 | 115 | private void SetCommonTileGlyphs() 116 | { 117 | DARK = _tileManager.GetGlyphNumByName("dark part of a room"); 118 | DIRT = _tileManager.GetGlyphNumByName("sub mine walls 0"); 119 | FLOOR = _tileManager.GetGlyphNumByName("floor of a room"); 120 | TILEABLEWALL = _tileManager.GetGlyphNumByName("tileable wall"); 121 | DARK = _tileManager.GetGlyphNumByName("dark part of a room"); 122 | DOOR = _tileManager.GetGlyphNumByName("closed door 1"); 123 | PLAYER = _tileManager.GetGlyphNumByName("valkyrie"); 124 | } 125 | 126 | /// 127 | /// Given the player input, advance the game one turn. 128 | /// 129 | /// 130 | public void DoTurn(PlayerInput playerInput) 131 | { 132 | if(_player != null) 133 | { 134 | // Attach or modify any components needed to the player. 135 | var position = _player.GetComponent(); 136 | if(INPUTMAP.ContainsKey(playerInput)) 137 | { 138 | var delta = INPUTMAP[playerInput]; 139 | var desired = delta + new Point(position.X, position.Y); 140 | var desiredComp = _player.GetComponent(); 141 | if(desiredComp == null) 142 | { 143 | desiredComp = new Destination(); 144 | _player.AddComponent(desiredComp); 145 | } 146 | desiredComp.X = desired.X; 147 | desiredComp.Y = desired.Y; 148 | } 149 | } 150 | 151 | // Cycle each entity through every system in turn. 152 | foreach(var entity in _entityManager.Entities) 153 | foreach(var system in _turnSystems) 154 | { 155 | system.Run(entity); 156 | } 157 | 158 | UpdateViews(); 159 | while(_messages.Count() > _messageLimit) 160 | { 161 | _messages.Dequeue(); 162 | } 163 | } 164 | 165 | 166 | void InitializePlayer() 167 | { 168 | _player = _actorManager.GetPlayerActor(PLAYER); 169 | ICell cell = GetWalkableCell(); 170 | _playerSiteDistance = _player.GetComponent(); 171 | _playerLocation = new Location() { X = cell.X, Y = cell.Y }; 172 | _player.AddComponent(_playerLocation); 173 | } 174 | 175 | ICell GetWalkableCell() 176 | { 177 | var location = random.Next(0, _spawnLocations.Count); 178 | var cell = _spawnLocations[location]; 179 | _spawnLocations.Remove(cell); 180 | return cell; 181 | } 182 | 183 | void PlaceMonsters() 184 | { 185 | var numMonsters = RogueSharp.DiceNotation.Dice.Roll("1D6+3"); 186 | for(int i = 0; i < numMonsters; i++) 187 | { 188 | var location = GetWalkableCell(); 189 | string name = $"Kobold"; 190 | var monster = _actorManager.CreateActor(60, name); 191 | monster.AddComponent(new Location(){X = location.X, Y = location.Y}); 192 | monster.AddComponent(new Faction(){Type = Factions.Monster}); 193 | monster.AddComponent(); 194 | Debug.WriteLine($"Spawned {name} ({location.X},{location.Y})"); 195 | } 196 | } 197 | 198 | /// 199 | /// Examine each cell and pick a suitable glyph for walls. 200 | /// 201 | void InitCellGlyphs() 202 | { 203 | int[,] mapArray = new int[_width, _height]; 204 | for(int x = 0; x < _width; x++) 205 | { 206 | for(int y = 0; y < _height; y++) 207 | { 208 | var cell = _map.GetCell(x,y); 209 | if(cell.IsWalkable) 210 | { 211 | _spawnLocations.Add(cell); 212 | } 213 | mapArray[x,y] = cell.IsWalkable ? 0 : 1; 214 | } 215 | } 216 | 217 | var detector = new MapFeatureDetector(mapArray); 218 | var walls = detector.FindWalls(); 219 | var doorways = detector.FindDoorways(); 220 | 221 | for(int x = 0; x < _width; x++) 222 | { 223 | for(int y = 0; y < _height; y++) 224 | { 225 | _floor[x,y] = DIRT; 226 | if(mapArray[x,y] == 0) 227 | { 228 | _floor[x,y] = FLOOR; 229 | if(doorways[x,y] > 0) {ConsiderAddDoor(x,y, (Orientation) doorways[x,y] -1);} 230 | } 231 | else 232 | { 233 | if(walls[x,y] == 1) {_floor[x,y] = TILEABLEWALL;} 234 | } 235 | } 236 | } 237 | } 238 | 239 | void ConsiderAddDoor(int x, int y, Orientation orientation) 240 | { 241 | var doorRoll = random.Next(100); 242 | if(doorRoll < _doorPercentChance) 243 | { 244 | var doorPoint = new Point(x, y); 245 | foreach(Point d in _doors) 246 | { 247 | // No side by side doors 248 | if(PointDistance(doorPoint, d) == 1) 249 | { 250 | return; 251 | } 252 | } 253 | var entity = _entityManager.CreateEntity(); 254 | var isDoor = new IsDoor(){Orientation = orientation, IsOpen = false}; 255 | entity.AddComponent(isDoor); 256 | var location = new Location(){X = x, Y = y}; 257 | entity.AddComponent(location); 258 | var glyph = new Glyph(){glyph = DOOR}; 259 | entity.AddComponent(glyph); 260 | _map.SetCellProperties(x, y, isTransparent: false, isWalkable: true); 261 | _doors.Add(doorPoint); 262 | var cell = _map.GetCell(x, y); 263 | _spawnLocations.Remove(cell); // Remove doors as a spawn location 264 | } 265 | } 266 | 267 | double PointDistance(Point a, Point b) 268 | { 269 | var dx = a.X - b.X; 270 | var dy = a.Y - b.Y; 271 | var dist = Math.Sqrt((dx * dx) + (dy * dy)); 272 | return dist; 273 | } 274 | 275 | /// 276 | /// Copy the private _floor to the public _floor_view 277 | /// 278 | void UpdateViews() 279 | { 280 | var circleView = GetFieldOfView(_playerLocation.X, _playerLocation.Y, _playerSiteDistance.Range, _map); 281 | var viewable = new List(); 282 | foreach(var cell in circleView) 283 | { 284 | viewable.Add(new Point(cell.X, cell.Y)); 285 | _map.AppendFov(cell.X, cell.Y, 0, true); 286 | } 287 | _viewable = new HashSet(viewable); 288 | 289 | if(_floor_view == null) 290 | { 291 | _floor_view = new int[_floor.GetLength(0), _floor.GetLength(1)]; 292 | } 293 | 294 | for(int x = 0; x < _floor.GetLength(0); x++ ) 295 | { 296 | for(int y = 0; y < _floor.GetLength(1); y++) 297 | { 298 | if(!_map.IsInFov(x, y)) 299 | { 300 | _floor_view[x,y] = DARK; 301 | } 302 | else 303 | { 304 | _floor_view[x,y] = _floor[x,y]; 305 | } 306 | } 307 | } 308 | } 309 | 310 | private static IEnumerable GetFieldOfView( int x, int y, int selectionSize, IMap map ) 311 | { 312 | List circleFov = new List(); 313 | var fieldOfView = new FieldOfView( map ); 314 | var cellsInFov = fieldOfView.ComputeFov( x, y, (int) ( selectionSize * 1.5 ), true ); 315 | var circle = map.GetCellsInCircle( x, y, selectionSize ).ToList(); 316 | foreach ( ICell cell in cellsInFov ) 317 | { 318 | if ( circle.Contains( cell ) ) 319 | { 320 | circleFov.Add( cell ); 321 | } 322 | } 323 | return circleFov; 324 | } 325 | 326 | private void BigRoom() 327 | { 328 | var bigroom = new RogueSharp.MapCreation.BorderOnlyMapCreationStrategy(_width, _height); 329 | _map = bigroom.CreateMap(); 330 | } 331 | 332 | private void RandomizeFloor() 333 | { 334 | var maxRooms = (int) Math.Sqrt(_height * _width) * 2; 335 | var randomRooms = new RogueSharp.MapCreation.RandomRoomsMapCreationStrategy(_width, _height, maxRooms, 10, 5); 336 | _map = randomRooms.CreateMap(); 337 | } 338 | 339 | private void RandomizeCave() 340 | { 341 | var randomCaves = new CaveMapCreationStrategy(_width, _height); 342 | _map = randomCaves.CreateMap(); 343 | } 344 | } 345 | 346 | } 347 | -------------------------------------------------------------------------------- /Engine/Engine.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard20;net461 5 | $(SolutionDir)\bin\$(Configuration)\$(AssemblyName)\ 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Engine/EngineConstants.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using RogueSharp; 3 | 4 | namespace MegaDungeon 5 | { 6 | /// 7 | /// A collection of constants used by the Engine class. 8 | /// 9 | public class EngineConstants 10 | { 11 | public static Point UP = new Point(0,-1); 12 | public static Point UPRIGHT = new Point(1, -1); 13 | public static Point RIGHT = new Point(1, 0); 14 | public static Point DOWNRIGHT = new Point(1, 1); 15 | public static Point DOWN = new Point(0, 1); 16 | public static Point DOWNLEFT = new Point(-1, 1); 17 | public static Point LEFT = new Point(-1, 0); 18 | public static Point UPLEFT = new Point(-1, -1); 19 | public static Point CENTER = new Point(0,0); 20 | 21 | public static Point[] COMPASSPOINTS = new[] { 22 | UPLEFT, UP, UPRIGHT, 23 | LEFT, CENTER, RIGHT, 24 | DOWNLEFT, DOWN, DOWNRIGHT 25 | }; 26 | 27 | public static Dictionary INPUTMAP = new Dictionary() 28 | { 29 | {PlayerInput.UP, UP}, 30 | {PlayerInput.UPRIGHT, UPRIGHT}, 31 | {PlayerInput.RIGHT, RIGHT}, 32 | {PlayerInput.DOWNRIGHT, DOWNRIGHT}, 33 | {PlayerInput.DOWN, DOWN}, 34 | {PlayerInput.DOWNLEFT, DOWNLEFT}, 35 | {PlayerInput.LEFT, LEFT}, 36 | {PlayerInput.UPLEFT, UPLEFT}, 37 | {PlayerInput.WAIT, CENTER}, 38 | }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Engine/EngineLogger.cs: -------------------------------------------------------------------------------- 1 | using EntityComponentSystemCSharp.Systems; 2 | 3 | namespace MegaDungeon 4 | { 5 | public class EngineLogger : ISystemLogger 6 | { 7 | Engine _engine; 8 | public EngineLogger(Engine engine) 9 | { 10 | _engine = engine; 11 | } 12 | 13 | public void Log(string message) 14 | { 15 | _engine._messages.Enqueue(message); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Engine/Filters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using RogueSharp; 4 | using FeatureDetector; 5 | using static MegaDungeon.EngineConstants; 6 | 7 | namespace MegaDungeon 8 | { 9 | /// 10 | /// Filters for matching small segments of the dungeon against to detect features. 11 | /// A simplified form of convalutional filters. 12 | /// 13 | public static class Filters 14 | { 15 | // 1 == impassable 16 | public static int[] Vertical = new []{ 17 | 0,1,0, 18 | 0,0,0, 19 | 0,1,0 20 | }; 21 | 22 | public static int[,] IdentityFilter = new int[,]{ 23 | {0,0,0}, 24 | {0,1,0}, 25 | {0,0,0} 26 | }; 27 | 28 | 29 | 30 | 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Engine/PlayerInput.cs: -------------------------------------------------------------------------------- 1 | namespace MegaDungeon 2 | { 3 | public enum PlayerInput 4 | { 5 | NONE, 6 | UP, 7 | UPRIGHT, 8 | RIGHT, 9 | DOWNRIGHT, 10 | DOWN, 11 | DOWNLEFT, 12 | LEFT, 13 | UPLEFT, 14 | WAIT 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Components.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using RogueSharp; 4 | using static EntityComponentSystemCSharp.EntityManager; 5 | 6 | 7 | namespace EntityComponentSystemCSharp.Components 8 | { 9 | /// 10 | /// Defines allowable components. Components SHOULD only have data members. 11 | /// Components SHOULD be simple to serialize. 12 | /// 13 | /// 14 | /// An entity may one have ONE of a a give component type. 15 | /// Use collections of entities for aggregates. 16 | /// 17 | public interface IComponent 18 | { 19 | 20 | } 21 | 22 | public class WanderingMonster : IComponent 23 | { 24 | } 25 | 26 | public class Attacked : IComponent 27 | { 28 | public Entity attacker; 29 | } 30 | 31 | public class Faction : IComponent 32 | { 33 | public MegaDungeon.Contracts.Factions Type; 34 | } 35 | 36 | public class AttackStat : IComponent 37 | { 38 | public int Power; 39 | public int Accuracy; 40 | } 41 | 42 | public class DefenseStat : IComponent 43 | { 44 | public int Chance; 45 | } 46 | 47 | public class SightStat : IComponent 48 | { 49 | public int Range; 50 | } 51 | 52 | public class Dead : IComponent 53 | { 54 | 55 | } 56 | 57 | public class Life : IComponent 58 | { 59 | public int Health; 60 | public int MaxHealth; 61 | } 62 | 63 | public class IsDoor : IComponent 64 | { 65 | public Orientation Orientation; 66 | public bool IsOpen; 67 | public bool Locked = false; 68 | } 69 | 70 | public class Destination : PointWrapper, IComponent 71 | { 72 | 73 | } 74 | 75 | public class Player : IComponent 76 | { 77 | 78 | } 79 | 80 | public class Actor : IComponent 81 | { 82 | public float Speed; 83 | public int Gold; 84 | public float Energy; 85 | } 86 | 87 | public class Glyph : IComponent 88 | { 89 | public int glyph = -1; 90 | } 91 | 92 | public class Location : PointWrapper, IComponent 93 | { 94 | } 95 | 96 | public class Demand : IComponent 97 | { 98 | public Dictionary Demands = new Dictionary(); 99 | } 100 | public class Item : IComponent 101 | { 102 | public string Type = ""; 103 | } 104 | 105 | public class Name : IComponent 106 | { 107 | public string NameString = null; 108 | } 109 | 110 | public class Producer : IComponent 111 | { 112 | public List ProducedItems = new List(); 113 | 114 | public class ProductionItem 115 | { 116 | public string product = null; 117 | public float rate = 0.0f; 118 | public float inprogress = 0; 119 | } 120 | } 121 | 122 | public class Inventory : IComponent 123 | { 124 | public List Items = new List(); 125 | public int Size = int.MaxValue; 126 | } 127 | 128 | public class Stackable : IComponent 129 | { 130 | } 131 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/DuplicateComponentException.cs: -------------------------------------------------------------------------------- 1 | namespace EntityComponentSystemCSharp 2 | { 3 | [System.Serializable] 4 | public class DuplicateComponentException : System.Exception 5 | { 6 | public DuplicateComponentException() { } 7 | public DuplicateComponentException(string message) : base(message) { } 8 | public DuplicateComponentException(string message, System.Exception inner) : base(message, inner) { } 9 | protected DuplicateComponentException( 10 | System.Runtime.Serialization.SerializationInfo info, 11 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { } 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/EntityComponentSystemCSharp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard20;net461 4 | true 5 | 6 | Library 7 | 8 | $(SolutionDir)\bin\$(Configuration)\$(AssemblyName)\ 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ..\lib\Newtonsoft.Json.dll 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/EntityExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EntityComponentSystemCSharp.Components; 3 | using static EntityComponentSystemCSharp.EntityManager; 4 | 5 | namespace EntityComponentSystemCSharp 6 | { 7 | /// 8 | /// Convienence methods for dealing with EntityManager entities. 9 | /// 10 | public static class EntityExtensions 11 | { 12 | /// 13 | /// 14 | /// 15 | /// 16 | /// List of components attached to entity 17 | public static IEnumerable GetComponents(this Entity entity) 18 | { 19 | return entity.Manager.GetAllComponentsOnEntity(entity); 20 | } 21 | 22 | /// 23 | /// Return the component of type T 24 | /// 25 | /// null if empty 26 | public static T GetComponent(this Entity entity) where T: class 27 | { 28 | return entity.Manager.GetComponent(entity); 29 | } 30 | 31 | public static void RemoveComponent(this Entity entity) where T: class 32 | { 33 | entity.Manager.RemoveComponent(entity); 34 | } 35 | 36 | public static void RemoveComponent(this Entity entity, IComponent component) 37 | { 38 | entity.Manager.RemoveComponent(entity.Id, component); 39 | } 40 | 41 | /// 42 | /// Permanently remove this enity and all it's components from the EntityManager 43 | /// 44 | /// 45 | public static void Destroy(this Entity entity) 46 | { 47 | entity.Manager.DestroyEntity(entity); 48 | } 49 | 50 | public static void AddComponent(this Entity entity, IComponent component) 51 | { 52 | entity.Manager.AddComponent(entity, component); 53 | } 54 | 55 | public static IComponent AddOrUpdateComponent(this Entity entity, IComponent component) 56 | { 57 | return entity.Manager.AddOrUpdateComponent(entity, component); 58 | } 59 | 60 | /// 61 | /// Adds and returns a new type T component to the entity. 62 | /// 63 | /// New component where T: IComponent 64 | public static T AddComponent(this Entity entity) where T: class, new() 65 | { 66 | CheckComponentAndThrow(); 67 | var component = (IComponent) new T(); 68 | entity.AddComponent(component); 69 | return (T) component; 70 | } 71 | 72 | public static bool HasComponent(this Entity entity) where T: class 73 | { 74 | CheckComponentAndThrow(); 75 | var component = entity.GetComponent(); 76 | return component != null; 77 | } 78 | 79 | /// 80 | /// Type check components to prevent random objects from being added. 81 | /// 82 | /// 83 | static void CheckComponentAndThrow() 84 | { 85 | if(!typeof(IComponent).IsAssignableFrom(typeof(T))) 86 | { 87 | throw new NotComponentException("You must specify a type that implement IComponent"); 88 | } 89 | } 90 | 91 | } 92 | 93 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/EntityManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text; 4 | using System.Collections.Generic; 5 | using EntityComponentSystemCSharp.Components; 6 | using Newtonsoft.Json; 7 | 8 | namespace EntityComponentSystemCSharp 9 | { 10 | /// 11 | /// Manages and stores entities and components. 12 | /// Based on http://entity-systems.wikidot.com/rdbms-beta 13 | /// 14 | public class EntityManager 15 | { 16 | // Entities are just and only integers. Entity class is a wrapper with a reference back to the entity 17 | // manager to allow extension methods to work more fluently. 18 | public sealed class Entity 19 | { 20 | private int _id; 21 | private EntityManager _manager; 22 | 23 | public int Id { get{ return _id; } } 24 | public EntityManager Manager { get { return _manager; } } 25 | 26 | internal Entity(int id, EntityManager manager) 27 | { 28 | _id = id; 29 | _manager = manager; 30 | } 31 | 32 | public override string ToString() 33 | { 34 | return $"Id = {_id}"; 35 | } 36 | } 37 | 38 | JsonSerializerSettings _serializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; 39 | 40 | public IEnumerable Entities => _entities.ToArray(); // Read Only version of current entities 41 | HashSet _entities = new HashSet(); 42 | 43 | // key is $"{entityInt}+{typeof(component).ToString()}" 44 | Dictionary _map = new Dictionary(); 45 | bool isFrozen = false; 46 | 47 | /// 48 | /// Add an entity to the collection 49 | /// 50 | /// New entity created 51 | public Entity CreateEntity() 52 | { 53 | if(isFrozen) 54 | { 55 | return new Entity(id: -1, manager: this); 56 | } 57 | 58 | var id = 0; 59 | while(_entities.Any(e => e.Id == id)) 60 | { 61 | id++; 62 | } 63 | 64 | var entity = new Entity(id, this); 65 | _entities.Add(entity); 66 | return entity; 67 | } 68 | 69 | /// 70 | /// Permanently remove an enitity and all it's components. The ID will be re-used. 71 | /// 72 | /// 73 | public void DestroyEntity(Entity entity) 74 | { 75 | if(isFrozen) 76 | { 77 | return; 78 | } 79 | 80 | _entities.Remove(entity); 81 | List removeKeys = new List(); 82 | foreach (var item in _map) 83 | { 84 | var pattern = $"{entity.Id}+"; 85 | if(item.Key.StartsWith(pattern)) 86 | { 87 | removeKeys.Add(item.Key); 88 | } 89 | } 90 | foreach(var key in removeKeys) 91 | { 92 | _map.Remove(key); 93 | } 94 | } 95 | 96 | public IEnumerable GetAllComponentsOfType() where T : class 97 | { 98 | var returnList = new List(); 99 | foreach(var entity in _entities) 100 | { 101 | var component = GetComponent(entity); 102 | if(component != null) 103 | { 104 | returnList.Add((T)component); 105 | } 106 | } 107 | return returnList; 108 | } 109 | 110 | public T GetComponent(Entity entity) where T: class 111 | { 112 | CheckComponentAndThrow(); 113 | return GetComponent(entity.Id); 114 | } 115 | 116 | public T GetComponent(int id) where T: class 117 | { 118 | var componentType = typeof(T); 119 | 120 | T returnVal = null; 121 | var key = GetMapKey(id, componentType); 122 | 123 | if(_map.ContainsKey(key)) 124 | { 125 | returnVal = (T)_map[key]; 126 | } 127 | return returnVal; 128 | } 129 | 130 | public List GetAllComponentsOnEntity(Entity entity) 131 | { 132 | return GetAllComponentsOnEntity(entity.Id); 133 | } 134 | 135 | private List GetAllComponentsOnEntity(int id) 136 | { 137 | var returnList = new List(); 138 | foreach(var entry in _map) 139 | { 140 | if(entry.Key.StartsWith($"{id}+")) 141 | { 142 | returnList.Add(entry.Value); 143 | } 144 | } 145 | return returnList; 146 | } 147 | 148 | public List GetAllEntitiesWithComponent() where T : class 149 | { 150 | Type componentType = typeof(T); 151 | var returnList = new List(); 152 | foreach(var entity in _entities) 153 | { 154 | var component = GetComponent(entity); 155 | if(component != null) 156 | { 157 | returnList.Add(entity); 158 | } 159 | } 160 | return returnList; 161 | } 162 | 163 | public void RemoveComponent(Entity entity) where T: class 164 | { 165 | var component = (IComponent) GetComponent(entity); 166 | if(component != null) 167 | { 168 | RemoveComponent(entity.Id, component); 169 | } 170 | } 171 | 172 | internal void RemoveComponent(int id, IComponent component) 173 | { 174 | if(isFrozen) 175 | { 176 | return; 177 | } 178 | 179 | var key = GetMapKey(id, component.GetType()); 180 | if(_map.ContainsKey(key)) 181 | { 182 | _map.Remove(key); 183 | } 184 | } 185 | 186 | public void AddComponent(Entity entity, IComponent component) 187 | { 188 | AddComponent(entity.Id, component); 189 | } 190 | 191 | public IComponent AddOrUpdateComponent(Entity entity, IComponent component) 192 | { 193 | var key = GetMapKey(entity.Id, component.GetType()); 194 | _map[key] = component; 195 | return component; 196 | } 197 | 198 | void AddComponent(int entityId, IComponent component) 199 | { 200 | if(isFrozen) 201 | { 202 | return; 203 | } 204 | 205 | var key = GetMapKey(entityId, component.GetType()); 206 | if(!_map.ContainsKey(key)) 207 | { 208 | _map.Add(key, component); 209 | } 210 | else 211 | { 212 | throw new DuplicateComponentException($"Entity already has a component of type {component.GetType()}. Modify existing or remove first."); 213 | } 214 | } 215 | 216 | internal bool HasComponent(Entity entity) where T : class 217 | { 218 | var component = GetComponent(entity); 219 | return component != null; 220 | } 221 | 222 | /// 223 | /// Prevent any changes to entities and components for debugging. 224 | /// 225 | public void Freeze() 226 | { 227 | isFrozen = true; 228 | } 229 | 230 | /// 231 | /// Allow changes to entities and components after Freeze-ing 232 | /// 233 | public void UnFreeze() 234 | { 235 | isFrozen = false; 236 | } 237 | 238 | public override string ToString() 239 | { 240 | var sb = new StringBuilder(); 241 | foreach(var item in _map) 242 | { 243 | sb.AppendLine(item.Key); 244 | } 245 | return sb.ToString(); 246 | } 247 | 248 | /// 249 | /// Returns a string template for creating more entities with the same parameters. 250 | /// 251 | /// 252 | /// 253 | public Dictionary GetEntityPrototype(Entity entity) 254 | { 255 | var components = entity.GetComponents(); 256 | var dict = new Dictionary(); 257 | foreach(var c in components) 258 | { 259 | dict.Add(c.GetType().Name, c); 260 | } 261 | return dict; 262 | } 263 | 264 | public Entity NewEntityFromPrototype(string prototype) 265 | { 266 | var components = JsonConvert.DeserializeObject>(prototype); 267 | var entity = CreateEntity(); 268 | foreach(var component in components) 269 | { 270 | var compStr = JsonConvert.SerializeObject(component.Value); 271 | compStr = compStr.Replace("{","{" + " \"$type\": " + $"\"EntityComponentSystemCSharp.Components.{component.Key}, EntityComponentSystemCSharp\",\n"); 272 | var actualComp = JsonConvert.DeserializeObject(compStr, _serializerSettings); 273 | entity.AddComponent(actualComp); 274 | } 275 | 276 | return entity; 277 | } 278 | 279 | string GetMapKey(int entity, Type componentType) 280 | { 281 | return $"{entity}+{componentType.ToString()}"; 282 | } 283 | 284 | void CheckComponentAndThrow() 285 | { 286 | if(!typeof(IComponent).IsAssignableFrom(typeof(T))) 287 | { 288 | throw new NotComponentException("You must specify a type that implement IComponent"); 289 | } 290 | } 291 | } 292 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/MissingComponentException.cs: -------------------------------------------------------------------------------- 1 | namespace EntityComponentSystemCSharp.Systems 2 | { 3 | [System.Serializable] 4 | public class MissingComponentException : System.Exception 5 | { 6 | public MissingComponentException() { } 7 | public MissingComponentException(string message) : base(message) { } 8 | public MissingComponentException(string message, System.Exception inner) : base(message, inner) { } 9 | protected MissingComponentException( 10 | System.Runtime.Serialization.SerializationInfo info, 11 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { } 12 | } 13 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/NotComponentException.cs: -------------------------------------------------------------------------------- 1 | namespace EntityComponentSystemCSharp 2 | { 3 | [System.Serializable] 4 | public class NotComponentException : System.Exception 5 | { 6 | public NotComponentException 7 | () { } 8 | public NotComponentException 9 | (string message) : base(message) { } 10 | public NotComponentException 11 | (string message, System.Exception inner) : base(message, inner) { } 12 | protected NotComponentException 13 | ( 14 | System.Runtime.Serialization.SerializationInfo info, 15 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { } 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Orientation.cs: -------------------------------------------------------------------------------- 1 | namespace EntityComponentSystemCSharp.Components 2 | { 3 | public enum Orientation 4 | { 5 | N, 6 | E, 7 | S, 8 | W 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/PointWrapper.cs: -------------------------------------------------------------------------------- 1 | namespace EntityComponentSystemCSharp.Components 2 | { 3 | /// 4 | /// RogueSharp implements Point as a struct, which is in effect sealed. 5 | /// Wrapper allows various components to be points with different names under the hood. 6 | /// 7 | public class PointWrapper 8 | { 9 | RogueSharp.Point point = new RogueSharp.Point(); 10 | 11 | public int X { get => point.X; set => point.X = value;} 12 | public int Y { get => point.Y; set => point.Y = value;} 13 | 14 | public PointWrapper() 15 | { 16 | 17 | } 18 | 19 | public PointWrapper(int value) 20 | { 21 | point = new RogueSharp.Point(value); 22 | } 23 | 24 | public PointWrapper(int x, int y) 25 | { 26 | point = new RogueSharp.Point(x,y); 27 | } 28 | 29 | PointWrapper(RogueSharp.Point point) 30 | { 31 | this.point = point; 32 | } 33 | 34 | public static PointWrapper Add(PointWrapper value1, PointWrapper value2) 35 | { 36 | var rpoint = RogueSharp.Point.Add(value1.point, value2.point); 37 | return new PointWrapper(rpoint); 38 | } 39 | 40 | public static float Distance(PointWrapper value1, PointWrapper value2) 41 | { 42 | return RogueSharp.Point.Distance(value1.point, value2.point); 43 | } 44 | 45 | public static PointWrapper Divide(PointWrapper value1, PointWrapper value2) 46 | { 47 | var rpoint = RogueSharp.Point.Divide(value1.point, value2.point); 48 | return new PointWrapper(rpoint); 49 | } 50 | 51 | public static PointWrapper Multiply(PointWrapper value1, PointWrapper value2) 52 | { 53 | var rpoint = RogueSharp.Point.Multiply(value1.point, value2.point); 54 | return new PointWrapper(rpoint); 55 | } 56 | 57 | public static PointWrapper Negate(PointWrapper value1) 58 | { 59 | var rpoint = RogueSharp.Point.Negate(value1.point); 60 | return new PointWrapper(rpoint); 61 | } 62 | 63 | public static PointWrapper Subtract(PointWrapper value1, PointWrapper value2) 64 | { 65 | var rpoint = RogueSharp.Point.Subtract(value1.point, value2.point); 66 | return new PointWrapper(rpoint); 67 | } 68 | 69 | public override bool Equals(object obj) 70 | { 71 | var wrapper = obj as PointWrapper; 72 | return wrapper != null && wrapper.point != null && point.Equals(obj); 73 | } 74 | 75 | // override object.GetHashCode 76 | public override int GetHashCode() 77 | { 78 | return point.GetHashCode(); 79 | } 80 | 81 | public override string ToString() 82 | { 83 | return point.ToString(); 84 | } 85 | 86 | public static PointWrapper operator +(PointWrapper value1, PointWrapper value2) 87 | { 88 | var wrapper = new PointWrapper((value1.point + value2.point)); 89 | return wrapper; 90 | } 91 | 92 | public static PointWrapper operator -(PointWrapper value1, PointWrapper value2) 93 | { 94 | var wrapper = new PointWrapper((value1.point - value2.point)); 95 | return wrapper; 96 | } 97 | 98 | public static PointWrapper operator *(PointWrapper value1, PointWrapper value2) 99 | { 100 | var wrapper = new PointWrapper((value1.point * value2.point)); 101 | return wrapper; 102 | } 103 | 104 | public static PointWrapper operator /(PointWrapper source, PointWrapper divisor) 105 | { 106 | var wrapper = new PointWrapper((source.point / divisor.point)); 107 | return wrapper; 108 | } 109 | public static bool operator ==(PointWrapper a, PointWrapper b) 110 | { 111 | return a?.point == b?.point; 112 | } 113 | 114 | public static bool operator !=(PointWrapper a, PointWrapper b) 115 | { 116 | return a?.point != b?.point; 117 | } 118 | 119 | 120 | } 121 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Systems/CombatSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EntityComponentSystemCSharp.Components; 3 | using RogueSharp; 4 | 5 | namespace EntityComponentSystemCSharp.Systems 6 | { 7 | 8 | public class CombatSystem : SystemBase, ISystem 9 | { 10 | Random _rand = new Random(); 11 | 12 | public CombatSystem(IEngine engine) : base(engine) 13 | { 14 | } 15 | 16 | public override void Run(EntityManager.Entity entity) 17 | { 18 | if(!entity.HasComponent()) {return;} 19 | 20 | var attacked = entity.GetComponent(); 21 | var alive = entity.GetComponent(); 22 | var attackStat = attacked.attacker.GetComponent(); 23 | var defense = entity.GetComponent(); 24 | if(alive != null && attackStat != null) 25 | { 26 | string attackerName = attacked.attacker.GetComponent()?.NameString ?? entity.Id.ToString(); 27 | string victimName = entity.GetComponent()?.NameString ?? entity.Id.ToString(); 28 | 29 | var hit = _rand.Next(100); 30 | if(hit < attackStat.Accuracy) 31 | { 32 | var damage = _rand.Next(attackStat.Power) + 1; 33 | if(defense != null) 34 | { 35 | if (hit > defense.Chance) 36 | { 37 | _logger.Log($"{attackerName} hit {victimName} for {damage} damage."); 38 | alive.Health -= damage; 39 | } 40 | } 41 | } 42 | else 43 | { 44 | _logger.Log($"{attackerName} missed {victimName}."); 45 | } 46 | } 47 | entity.RemoveComponent(); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Systems/DemandSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using EntityComponentSystemCSharp; 4 | using EntityComponentSystemCSharp.Components; 5 | using static EntityComponentSystemCSharp.EntityManager; 6 | 7 | namespace EntityComponentSystemCSharp.Systems 8 | { 9 | 10 | public class DemandSystem : SystemBase, ISystem 11 | { 12 | public DemandSystem(IEngine engine) : base(engine) 13 | { 14 | } 15 | 16 | public override void Run(Entity entity) 17 | { 18 | if(!entity.HasComponent()){return;} 19 | 20 | var demand = entity.GetComponent(); 21 | var inventory = entity.GetComponent(); 22 | if(demand != null) 23 | { 24 | foreach(var d in demand.Demands) 25 | { 26 | var items = GetItemsFromInventory(entity, d.Key); 27 | var numToRemove = Math.Min(items.Length, d.Value); 28 | for(int i = 0; i < numToRemove; i++) 29 | { 30 | inventory.Items.Remove(items[i]); 31 | } 32 | } 33 | } 34 | } 35 | 36 | Entity[] GetItemsFromInventory(Entity entity, string type) 37 | { 38 | var inventory = entity.GetComponent(); 39 | if(inventory == null) 40 | { 41 | throw new MissingComponentException("Production requires an inventory for storage."); 42 | } 43 | var returnList = new List(); 44 | foreach(var item in inventory.Items) 45 | { 46 | var itemComponent = item.GetComponent(); 47 | if(itemComponent != null && itemComponent.Type == type) 48 | { 49 | returnList.Add(item); 50 | } 51 | } 52 | return returnList.ToArray(); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Systems/EnergySystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using RogueSharp; 5 | using EntityComponentSystemCSharp.Components; 6 | 7 | namespace EntityComponentSystemCSharp.Systems 8 | { 9 | public class EnergySystem : SystemBase, ISystem 10 | { 11 | public EnergySystem(IEngine engine) : base(engine) 12 | { 13 | } 14 | 15 | public override void Run(EntityManager.Entity entity) 16 | { 17 | if(!entity.HasComponent()){return;} 18 | 19 | var actor = entity.GetComponent(); 20 | actor.Energy += actor.Speed; 21 | 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Systems/HealthSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EntityComponentSystemCSharp.Components; 3 | using RogueSharp; 4 | 5 | namespace EntityComponentSystemCSharp.Systems 6 | { 7 | public class HealthSystem : SystemBase, ISystem 8 | { 9 | int CORPSE = 636; 10 | Random rand = new Random(); 11 | public HealthSystem(IEngine engine) : base(engine) 12 | { 13 | } 14 | 15 | public override void Run(EntityManager.Entity entity) 16 | { 17 | var life = entity.GetComponent(); 18 | if(life == null) {return;} 19 | 20 | if(life.Health < life.MaxHealth) 21 | { 22 | var regenRole = rand.Next(1000); 23 | if (regenRole < life.MaxHealth) 24 | { 25 | life.Health++; 26 | } 27 | } 28 | 29 | if(life.Health <= 0) 30 | { 31 | var nameComponent = entity.GetComponent(); 32 | string name = ""; 33 | if(nameComponent != null) 34 | { 35 | name = nameComponent.NameString; 36 | } 37 | 38 | _logger.Log($"{name}({entity.Id.ToString()}) has run out of hitpoints and died."); 39 | 40 | entity.RemoveComponent(); 41 | entity.RemoveComponent(); 42 | entity.AddComponent(); 43 | 44 | var glyph = entity.GetComponent(); 45 | glyph.glyph = CORPSE; 46 | } 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Systems/IEngine.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EntityComponentSystemCSharp.Systems; 3 | using MegaDungeon.Contracts; 4 | using RogueSharp; 5 | 6 | namespace EntityComponentSystemCSharp 7 | { 8 | public interface IEngine 9 | { 10 | EntityManager GetEntityManager(); 11 | RogueSharp.IMap GetMap(); 12 | ISystemLogger GetLogger(); 13 | HashSet GetPlayerViewable(); 14 | Point GetPlayerLocation(); 15 | ITileManager GetTileManager(); 16 | } 17 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Systems/ISystem.cs: -------------------------------------------------------------------------------- 1 | namespace EntityComponentSystemCSharp.Systems 2 | { 3 | public interface ISystem 4 | { 5 | void Run(EntityManager.Entity entity); 6 | } 7 | 8 | public interface ISystemLogger 9 | { 10 | void Log(string message); 11 | } 12 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Systems/MovementSystem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using EntityComponentSystemCSharp.Components; 4 | using static EntityComponentSystemCSharp.EntityManager; 5 | using RogueSharp; 6 | 7 | namespace EntityComponentSystemCSharp.Systems 8 | { 9 | public class MovementSystem : SystemBase, ISystem 10 | { 11 | bool _isClear = true; 12 | RogueSharp.PathFinder _pathfinder; 13 | int _nsOpenDoorGlyph, _ewOpenDoorGlyph; 14 | public MovementSystem(IEngine engine) : base(engine) 15 | { 16 | _pathfinder = new RogueSharp.PathFinder(_map, 1); 17 | var tm = _engine.GetTileManager(); 18 | _nsOpenDoorGlyph = tm.GetGlyphNumByName("open door NS"); 19 | _ewOpenDoorGlyph = tm.GetGlyphNumByName("open door EW"); 20 | } 21 | 22 | public override void Run(Entity entity) 23 | { 24 | if(!(entity.HasComponent() && 25 | entity.HasComponent() && 26 | entity.GetComponent().Energy >= 10)) 27 | {return;} 28 | 29 | var locationEntities = _em.GetAllEntitiesWithComponent() 30 | .Where(e => e.HasComponent() || e.HasComponent()); 31 | 32 | entity.GetComponent().Energy -= 10; 33 | var allComponents = entity.GetComponents(); 34 | var current = entity.GetComponent(); 35 | var desired = entity.GetComponent(); 36 | if(_map != null && desired != null && desired.X >= 0 && desired.X < _map.Width && desired.Y >= 0 && desired.Y < _map.Height) 37 | { 38 | var start = _map.GetCell(current.X, current.Y); 39 | var dest = _map.GetCell(desired.X, desired.Y); 40 | var path = _pathfinder.TryFindShortestPath(start, dest); 41 | _isClear = true; 42 | if(path != null && path.Length > 1) 43 | { 44 | var next = path.StepForward(); 45 | ResolveCollisions(entity, locationEntities, current, next); 46 | if (_isClear) 47 | { 48 | current.X = next.X; 49 | current.Y = next.Y; 50 | } 51 | } 52 | } 53 | } 54 | 55 | 56 | void ResolveCollisions(Entity entity, IEnumerable locationEntities, Location current, ICell next) 57 | { 58 | _isClear = true; 59 | foreach(var other in locationEntities) 60 | { 61 | var othersLocation = other.GetComponent(); 62 | if (othersLocation.X == next.X && othersLocation.Y == next.Y) 63 | { 64 | var handled = DoorCheck(other, othersLocation); 65 | if(!handled){ResolveAttack(entity, current, other, othersLocation);} 66 | } 67 | } 68 | } 69 | 70 | bool DoorCheck(Entity other, Location othersLocation) 71 | { 72 | var handled = false; 73 | if(other.HasComponent()) 74 | { 75 | var door = other.GetComponent(); 76 | var glyph = other.GetComponent(); 77 | 78 | // TODO: Check for locked doors. 79 | 80 | door.IsOpen = true; 81 | if(door.Orientation == Orientation.N || door.Orientation == Orientation.S) 82 | { 83 | glyph.glyph = _nsOpenDoorGlyph; 84 | } 85 | else 86 | { 87 | glyph.glyph = _ewOpenDoorGlyph; 88 | } 89 | _map.SetCellProperties(othersLocation.X, othersLocation.Y, isTransparent: true, isWalkable: true); 90 | handled = true; 91 | } 92 | return handled; 93 | } 94 | 95 | bool ResolveAttack(Entity entity, Location current, Entity other, Location othersLocation) 96 | { 97 | var handled = false; 98 | var myFaction = entity.GetComponent(); 99 | var theirFaction = other.GetComponent(); 100 | var theirAttacked = other.GetComponent(); 101 | 102 | // Check to see if the two are eligible to swap. 103 | // Must be same faction and target not under (unresolved) attack. 104 | if (myFaction != null && 105 | theirFaction != null && 106 | theirAttacked == null && 107 | myFaction.Type == theirFaction.Type) 108 | { 109 | othersLocation.X = current.X; 110 | othersLocation.Y = current.Y; 111 | handled = true; 112 | } 113 | else 114 | { 115 | other.AddOrUpdateComponent(new Attacked() { attacker = entity }); 116 | _isClear = false; //Attacking cancels move 117 | handled = true; 118 | } 119 | return handled; 120 | } 121 | } 122 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Systems/ProductionSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EntityComponentSystemCSharp.Components; 3 | using RogueSharp; 4 | 5 | namespace EntityComponentSystemCSharp.Systems 6 | { 7 | public class ProductionSystem : SystemBase, ISystem 8 | { 9 | public ProductionSystem(IEngine engine) : base(engine) 10 | { 11 | } 12 | 13 | public override void Run(EntityManager.Entity entity) 14 | { 15 | if(!entity.HasComponent()){return;} 16 | 17 | var production = entity.GetComponent(); 18 | 19 | foreach(var product in production.ProducedItems) 20 | { 21 | product.inprogress += product.rate; 22 | var wholeItems = (int)(product.inprogress); 23 | product.inprogress =- wholeItems; 24 | var inventory = entity.GetComponent(); 25 | var numToAdd = Math.Min(inventory.Size, wholeItems); 26 | for(int i = 0; i < numToAdd; i++) 27 | { 28 | var item = _em.CreateEntity(); 29 | item.AddComponent(new Item(){Type = product.product}); 30 | inventory.Items.Add(item); 31 | } 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Systems/StackSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using EntityComponentSystemCSharp; 4 | using EntityComponentSystemCSharp.Components; 5 | using RogueSharp; 6 | using static EntityComponentSystemCSharp.EntityManager; 7 | 8 | namespace EntityComponentSystemCSharp.Systems 9 | { 10 | public class StackSystem : SystemBase, ISystem 11 | { 12 | public StackSystem(IEngine engine) : base(engine) 13 | { 14 | } 15 | 16 | public override void Run(Entity entity) 17 | { 18 | throw new NotImplementedException(); 19 | } 20 | 21 | public Dictionary GetStacks(Entity entity) 22 | { 23 | var results = new Dictionary(); 24 | var inventory = entity.GetComponent(); 25 | if(inventory != null) 26 | { 27 | foreach(var item in inventory.Items) 28 | { 29 | var itemComponent = item.GetComponent(); 30 | 31 | if(itemComponent != null && item.HasComponent()) 32 | { 33 | if(!results.ContainsKey(itemComponent.Type)) 34 | { 35 | results.Add(itemComponent.Type, 0); 36 | } 37 | results[itemComponent.Type] += 1; 38 | } 39 | } 40 | } 41 | return results; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Systems/SystemBase.cs: -------------------------------------------------------------------------------- 1 | using EntityComponentSystemCSharp; 2 | using static EntityComponentSystemCSharp.EntityManager; 3 | using RogueSharp; 4 | 5 | 6 | namespace EntityComponentSystemCSharp.Systems 7 | { 8 | public abstract class SystemBase: ISystem 9 | { 10 | protected readonly EntityManager _em; 11 | protected readonly ISystemLogger _logger; 12 | protected readonly IMap _map; 13 | protected IEngine _engine; 14 | public SystemBase(IEngine engine) 15 | { 16 | _em = engine.GetEntityManager(); 17 | _logger = engine.GetLogger(); 18 | _map = engine.GetMap(); 19 | _engine = engine; 20 | } 21 | public abstract void Run(Entity entity); 22 | } 23 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Systems/WanderingMonsterSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using EntityComponentSystemCSharp.Components; 4 | using RogueSharp; 5 | 6 | namespace EntityComponentSystemCSharp.Systems 7 | { 8 | /// 9 | /// Entities with the wandering monster component will wander around at random 10 | /// and attack the player if they see them. 11 | /// 12 | public class WanderingMonsterSystem : SystemBase 13 | { 14 | Random rand = new Random(); 15 | List walkable = new List(); 16 | public WanderingMonsterSystem(IEngine engine): base(engine) 17 | { 18 | foreach(var cell in _map.GetAllCells()) 19 | { 20 | if(cell.IsWalkable) 21 | { 22 | walkable.Add(cell); 23 | } 24 | } 25 | } 26 | 27 | public override void Run(EntityManager.Entity entity) 28 | { 29 | if(!entity.HasComponent()){return;} 30 | if(!entity.HasComponent()){return;} 31 | 32 | var actual = entity.GetComponent(); 33 | var desired = entity.GetComponent(); 34 | 35 | var point = new Point(actual.X, actual.Y); 36 | if (_engine.GetPlayerViewable().Contains(point)) 37 | { 38 | desired = new Destination() {X =_engine.GetPlayerLocation().X, Y = _engine.GetPlayerLocation().Y}; 39 | entity.AddOrUpdateComponent((IComponent)desired); 40 | } 41 | else if(desired == null || desired == actual) 42 | { 43 | entity.RemoveComponent(); 44 | var randCell = walkable[rand.Next(0, walkable.Count)]; 45 | desired = entity.AddComponent(); 46 | desired.X = randCell.X; 47 | desired.Y = randCell.Y; 48 | } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Test/EntityManagerTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using NUnit.Framework; 3 | using EntityComponentSystemCSharp.Components; 4 | 5 | namespace EntityComponentSystemCSharp 6 | { 7 | [TestFixture] 8 | public class EntityManagerTests 9 | { 10 | 11 | [Test] 12 | public void CreateEntityTest() 13 | { 14 | var _em = new EntityManager(); 15 | var entity = _em.CreateEntity(); 16 | Assert.IsNotNull(entity); 17 | } 18 | 19 | [Test] 20 | public void KillEntityTest() 21 | { 22 | var _em = new EntityManager(); 23 | var entity = _em.CreateEntity(); 24 | var tag = new Name(); 25 | entity.AddComponent(tag); 26 | entity.Destroy(); 27 | var entities = _em.GetAllEntitiesWithComponent(); 28 | Assert.AreEqual(0, entities.Count); 29 | } 30 | 31 | [Test] 32 | public void AddAndGetComponentTest() 33 | { 34 | var _em = new EntityManager(); 35 | var entity = _em.CreateEntity(); 36 | var tag = new Name(){NameString = "test"}; 37 | entity.AddComponent(tag); 38 | var actaul = entity.GetComponent(); 39 | Assert.AreEqual(tag, actaul); 40 | } 41 | 42 | [Test] 43 | public void RemoveComponentTest() 44 | { 45 | var _em = new EntityManager(); 46 | var entity = _em.CreateEntity(); 47 | var tag = new Name(){NameString = "test"}; 48 | entity.AddComponent(tag); 49 | entity.RemoveComponent(tag); 50 | var actual = entity.GetComponent(); 51 | Assert.Null(actual); 52 | 53 | entity.AddComponent(tag); 54 | entity.RemoveComponent(); 55 | actual = entity.GetComponent(); 56 | Assert.Null(actual); 57 | } 58 | 59 | [Test] 60 | public void RemoveComponentGenericTest() 61 | { 62 | var _em = new EntityManager(); 63 | var entity = _em.CreateEntity(); 64 | var tag = new Name(){NameString = "test"}; 65 | entity.AddComponent(tag); 66 | entity.RemoveComponent(); 67 | var actual = entity.GetComponent(); 68 | Assert.Null(actual); 69 | } 70 | 71 | [Test] 72 | public void NotComponentException() 73 | { 74 | var _em = new EntityManager(); 75 | var entity = _em.CreateEntity(); 76 | Assert.That(( ) => entity.GetComponent(), Throws.TypeOf()); 77 | } 78 | 79 | [Test] 80 | public void GetAllComponentsOnEntityTest() 81 | { 82 | var _em = new EntityManager(); 83 | var entity = _em.CreateEntity(); 84 | var tag = new Name(){NameString = "test"}; 85 | var producer = new Producer(); 86 | entity.AddComponent(tag); 87 | entity.AddComponent(producer); 88 | var allComponents = entity.GetComponents(); 89 | Assert.AreEqual(2, allComponents.Count()); 90 | } 91 | 92 | [Test] 93 | public void GetComponentOfTypeTest() 94 | { 95 | var _em = new EntityManager(); 96 | var entity = _em.CreateEntity(); 97 | var tag = new Name(){NameString = "test"}; 98 | var producer = new Producer(); 99 | entity.AddComponent(tag); 100 | entity.AddComponent(producer); 101 | var actual = entity.GetComponent(); 102 | Assert.AreEqual(tag, actual); 103 | } 104 | 105 | [Test] 106 | public void GetAllComponentsOfTypeTest() 107 | { 108 | var _em = new EntityManager(); 109 | var entity = _em.CreateEntity(); 110 | var tag = new Name(){NameString = "test"}; 111 | var producer = new Producer(); 112 | entity.AddComponent(tag); 113 | entity.AddComponent(producer); 114 | 115 | var entity2 = _em.CreateEntity(); 116 | var tag2 = new Name(){NameString = "test2"}; 117 | var producer2 = new Producer(); 118 | entity2.AddComponent(tag2); 119 | entity2.AddComponent(producer2); 120 | 121 | var tagComponents = _em.GetAllComponentsOfType(); 122 | Assert.AreEqual(2, tagComponents.Count()); 123 | Assert.AreEqual(tagComponents.First().GetType(), typeof(Name)); 124 | } 125 | 126 | [Test] 127 | public void GetAllEntitiesWithComponentTest() 128 | { 129 | var _em = new EntityManager(); 130 | _em.CreateEntity(); 131 | var entity = _em.CreateEntity(); 132 | var tag = new Name(){NameString = "test"}; 133 | var producer = new Producer(); 134 | entity.AddComponent(tag); 135 | entity.AddComponent(producer); 136 | 137 | var entity2 = _em.CreateEntity(); 138 | var producer2 = new Producer(); 139 | entity2.AddComponent(producer2); 140 | 141 | var entities = _em.GetAllEntitiesWithComponent(); 142 | Assert.AreEqual(2, entities.Count); 143 | Assert.IsTrue(entities.Contains(entity)); 144 | Assert.IsTrue(entities.Contains(entity2)); 145 | } 146 | 147 | [Test] 148 | public void HasComponentTest() 149 | { 150 | var _em = new EntityManager(); 151 | var entity = _em.CreateEntity(); 152 | var tag = new Name(){NameString = "test"}; 153 | entity.AddComponent(tag); 154 | var hasTag = _em.HasComponent(entity); 155 | Assert.IsTrue(hasTag); 156 | 157 | var hasProducer = _em.HasComponent(entity); 158 | Assert.IsFalse(hasProducer); 159 | } 160 | 161 | [Test] 162 | public void FreezeTest() 163 | { 164 | var _em = new EntityManager(); 165 | _em.Freeze(); 166 | var negaEntity = _em.CreateEntity(); 167 | var count = _em.Entities.Count(); 168 | Assert.AreEqual(0, count); 169 | _em.UnFreeze(); 170 | 171 | var entity = _em.CreateEntity(); 172 | _em.Freeze(); 173 | var tag = new Name(); 174 | entity.AddComponent(tag); 175 | var entities = _em.GetAllEntitiesWithComponent(); 176 | Assert.AreEqual(0, entities.Count); 177 | } 178 | 179 | [Test] 180 | public void UnfreezeTest() 181 | { 182 | var _em = new EntityManager(); 183 | var entity = _em.CreateEntity(); 184 | _em.Freeze(); 185 | _em.UnFreeze(); 186 | var tag = new Name(); 187 | entity.AddComponent(tag); 188 | var entities = _em.GetAllEntitiesWithComponent(); 189 | Assert.AreEqual(1, entities.Count); 190 | } 191 | 192 | [Test] 193 | public void DuplicateComponentsTest() 194 | { 195 | var _em = new EntityManager(); 196 | var entity = _em.CreateEntity(); 197 | var tag1 = new Name(); 198 | var tag2 = new Name(); 199 | entity.AddComponent(tag1); 200 | Assert.That(( ) => entity.AddComponent(tag2), Throws.TypeOf()); 201 | } 202 | } 203 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Test/EntityPrototypeTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Reflection; 4 | using System.Diagnostics; 5 | using NUnit.Framework; 6 | using EntityComponentSystemCSharp; 7 | using EntityComponentSystemCSharp.Components; 8 | using System.Collections.Generic; 9 | using Newtonsoft.Json; 10 | using static EntityComponentSystemCSharp.EntityManager; 11 | using MegaDungeon.Contracts; 12 | 13 | namespace EntityComponentSystemCSharp.Test 14 | { 15 | [TestFixture] 16 | public class EntityPrototypeTests 17 | { 18 | [Test] 19 | public void GetEntityDetailsTest() 20 | { 21 | var em = new EntityManager(); 22 | var entity = em.CreateEntity(); 23 | entity.AddComponent(new Location(){X = 1, Y = 2}); 24 | entity.AddComponent(); 25 | var prototype = em.GetEntityPrototype(entity); 26 | Assert.NotNull(prototype["Actor"]); 27 | } 28 | 29 | [Test] 30 | public void RoundTripTest() 31 | { 32 | var em = new EntityManager(); 33 | var entity = em.CreateEntity(); 34 | entity.AddComponent(new Location(){X = 1, Y = 2}); 35 | entity.AddComponent(); 36 | var prototype = em.GetEntityPrototype(entity); 37 | var protoString = JsonConvert.SerializeObject(prototype); 38 | var newEntity = em.NewEntityFromPrototype(protoString); 39 | var location = newEntity.GetComponent(); 40 | Assert.AreEqual(1, location.X); 41 | Assert.AreEqual(2, location.Y); 42 | Assert.AreNotEqual(entity.Id, newEntity.Id); 43 | } 44 | 45 | [Test] 46 | public void CreateRealEntityPrototype() 47 | { 48 | var em = new EntityManager(); 49 | var actor1 = CreateActor(em, 0, "Giant Ant", 10, 5, 2, 50, 9.5F); 50 | var actor2 = CreateActor(em, 71, "Goblin", 5, 1, 2, 50); 51 | var actor3 = CreateActor(em, 60, "Kobold"); 52 | var serial1 = em.GetEntityPrototype(actor1); 53 | var serial2 = em.GetEntityPrototype(actor2); 54 | var serial3 = em.GetEntityPrototype(actor3); 55 | var dict = new Dictionary>(){ 56 | {"Giant Ant", serial1}, 57 | {"Goblin", serial2}, 58 | {"Kobold", serial3}}; 59 | var json = JsonConvert.SerializeObject(dict, Formatting.Indented); 60 | var codebase = System.Reflection.Assembly.GetExecutingAssembly().CodeBase; 61 | var testPath = (new Uri(Assembly.GetExecutingAssembly().CodeBase)).LocalPath; 62 | var protoTypePath = Path.Combine(Path.GetDirectoryName(testPath), "EntityPrototypes.json"); 63 | System.IO.File.WriteAllText(protoTypePath, json); 64 | } 65 | 66 | EntityManager.Entity CreateActor(EntityManager em, int glyph, string name = "actor", int maxHealth = 1,int defense = 1, int power = 1,int accuracy = 70, float speed = 8.0F) 67 | { 68 | var actor = em.CreateEntity(); 69 | actor.AddComponent(new Actor(){Gold = 0, Speed = speed}); 70 | actor.AddComponent(new AttackStat(){Accuracy = accuracy, Power = power}); 71 | actor.AddComponent(new DefenseStat(){Chance = defense}); 72 | actor.AddComponent(new Life(){Health = maxHealth, MaxHealth = maxHealth}); 73 | actor.AddComponent(new Name(){NameString = name}); 74 | actor.AddComponent(new Glyph{glyph = glyph}); 75 | 76 | actor.AddComponent(new Faction(){Type = Factions.Monster}); 77 | actor.AddComponent(); 78 | return actor; 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Test/MockEngine.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using EntityComponentSystemCSharp.Systems; 3 | using MegaDungeon.Contracts; 4 | using RogueSharp; 5 | 6 | namespace EntityComponentSystemCSharp 7 | { 8 | public class MockEngine : IEngine 9 | { 10 | EntityManager _em; 11 | ISystemLogger _logger; 12 | IMap _map; 13 | public MockEngine(EntityManager entityManager, ISystemLogger systemLogger, IMap map) 14 | { 15 | _em = entityManager; 16 | _logger = systemLogger; 17 | _map = map; 18 | } 19 | public EntityManager GetEntityManager() 20 | { 21 | return _em; 22 | } 23 | 24 | public ISystemLogger GetLogger() 25 | { 26 | return _logger; 27 | } 28 | 29 | public IMap GetMap() 30 | { 31 | return _map; 32 | } 33 | 34 | public Point GetPlayerLocation() 35 | { 36 | throw new System.NotImplementedException(); 37 | } 38 | 39 | public HashSet GetPlayerViewable() 40 | { 41 | throw new System.NotImplementedException(); 42 | } 43 | 44 | public ITileManager GetTileManager() 45 | { 46 | throw new System.NotImplementedException(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Test/MockLogger.cs: -------------------------------------------------------------------------------- 1 | namespace EntityComponentSystemCSharp 2 | { 3 | public class MockLogger : EntityComponentSystemCSharp.Systems.ISystemLogger 4 | { 5 | public void Log(string message) 6 | { 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Test/ProductionTests.MockMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using RogueSharp; 3 | using System.Collections.Generic; 4 | using System.Collections.ObjectModel; 5 | 6 | namespace EntityComponentSystemCSharp 7 | { 8 | 9 | public class MockMap : RogueSharp.IMap 10 | { 11 | public int Width => 0; 12 | 13 | public int Height => 0; 14 | 15 | public ReadOnlyCollection AppendFov(int xOrigin, int yOrigin, int radius, bool lightWalls) 16 | { 17 | throw new NotImplementedException(); 18 | } 19 | 20 | public ICell CellFor(int index) 21 | { 22 | throw new NotImplementedException(); 23 | } 24 | 25 | public void Clear() 26 | { 27 | throw new NotImplementedException(); 28 | } 29 | 30 | public void Clear(bool isTransparent, bool isWalkable) 31 | { 32 | throw new NotImplementedException(); 33 | } 34 | 35 | public IMap Clone() 36 | { 37 | throw new NotImplementedException(); 38 | } 39 | 40 | public ReadOnlyCollection ComputeFov(int xOrigin, int yOrigin, int radius, bool lightWalls) 41 | { 42 | throw new NotImplementedException(); 43 | } 44 | 45 | public void Copy(IMap sourceMap) 46 | { 47 | throw new NotImplementedException(); 48 | } 49 | 50 | public void Copy(IMap sourceMap, int left, int top) 51 | { 52 | throw new NotImplementedException(); 53 | } 54 | 55 | public IEnumerable GetAllCells() 56 | { 57 | throw new NotImplementedException(); 58 | } 59 | 60 | public IEnumerable GetBorderCellsInCircle(int xCenter, int yCenter, int radius) 61 | { 62 | throw new NotImplementedException(); 63 | } 64 | 65 | public IEnumerable GetBorderCellsInDiamond(int xCenter, int yCenter, int distance) 66 | { 67 | throw new NotImplementedException(); 68 | } 69 | 70 | public IEnumerable GetBorderCellsInSquare(int xCenter, int yCenter, int distance) 71 | { 72 | throw new NotImplementedException(); 73 | } 74 | 75 | public ICell GetCell(int x, int y) 76 | { 77 | throw new NotImplementedException(); 78 | } 79 | 80 | public IEnumerable GetCellsAlongLine(int xOrigin, int yOrigin, int xDestination, int yDestination) 81 | { 82 | throw new NotImplementedException(); 83 | } 84 | 85 | public IEnumerable GetCellsInCircle(int xCenter, int yCenter, int radius) 86 | { 87 | throw new NotImplementedException(); 88 | } 89 | 90 | public IEnumerable GetCellsInColumns(params int[] columnNumbers) 91 | { 92 | throw new NotImplementedException(); 93 | } 94 | 95 | public IEnumerable GetCellsInDiamond(int xCenter, int yCenter, int distance) 96 | { 97 | throw new NotImplementedException(); 98 | } 99 | 100 | public IEnumerable GetCellsInRows(params int[] rowNumbers) 101 | { 102 | throw new NotImplementedException(); 103 | } 104 | 105 | public IEnumerable GetCellsInSquare(int xCenter, int yCenter, int distance) 106 | { 107 | throw new NotImplementedException(); 108 | } 109 | 110 | public int IndexFor(int x, int y) 111 | { 112 | throw new NotImplementedException(); 113 | } 114 | 115 | public int IndexFor(ICell cell) 116 | { 117 | throw new NotImplementedException(); 118 | } 119 | 120 | public void Initialize(int width, int height) 121 | { 122 | throw new NotImplementedException(); 123 | } 124 | 125 | public bool IsExplored(int x, int y) 126 | { 127 | throw new NotImplementedException(); 128 | } 129 | 130 | public bool IsInFov(int x, int y) 131 | { 132 | throw new NotImplementedException(); 133 | } 134 | 135 | public bool IsTransparent(int x, int y) 136 | { 137 | throw new NotImplementedException(); 138 | } 139 | 140 | public bool IsWalkable(int x, int y) 141 | { 142 | throw new NotImplementedException(); 143 | } 144 | 145 | public void Restore(MapState state) 146 | { 147 | throw new NotImplementedException(); 148 | } 149 | 150 | public MapState Save() 151 | { 152 | throw new NotImplementedException(); 153 | } 154 | 155 | public void SetCellProperties(int x, int y, bool isTransparent, bool isWalkable, bool isExplored) 156 | { 157 | throw new NotImplementedException(); 158 | } 159 | 160 | public void SetCellProperties(int x, int y, bool isTransparent, bool isWalkable) 161 | { 162 | throw new NotImplementedException(); 163 | } 164 | 165 | public string ToString(bool useFov) 166 | { 167 | throw new NotImplementedException(); 168 | } 169 | } 170 | 171 | } 172 | 173 | -------------------------------------------------------------------------------- /EntityComponentSystemCSharp/Test/ProductionTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using EntityComponentSystemCSharp.Components; 3 | using EntityComponentSystemCSharp.Systems; 4 | using System.Linq; 5 | 6 | namespace EntityComponentSystemCSharp 7 | { 8 | 9 | public partial class ProductionSystemTests 10 | { 11 | MockEngine _mockEngine; 12 | [OneTimeSetUp] 13 | public void OneTimeSetUp() 14 | { 15 | _mockEngine = new MockEngine(new EntityManager(), new MockLogger(), new MockMap()); 16 | } 17 | 18 | [Test] 19 | public void ConstructorTest() 20 | { 21 | var mockEngine = new MockEngine(new EntityManager(), new MockLogger(), new MockMap()); 22 | var productionSystem = new ProductionSystem(mockEngine); 23 | } 24 | 25 | [Test] 26 | public void ProductionTest() 27 | { 28 | var em = new EntityManager(); 29 | var entity = em.CreateEntity(); 30 | var producer = CreateWidgetFactory(); 31 | entity.AddComponent( producer); 32 | 33 | var inventory = new Inventory(); 34 | entity.AddComponent( inventory); 35 | 36 | var productionSystem = new ProductionSystem(_mockEngine); 37 | productionSystem.Run(entity); 38 | 39 | Assert.AreEqual(11, inventory.Items.Count); 40 | } 41 | 42 | 43 | [Test] 44 | public void InventoryLimitTest() 45 | { 46 | var em = new EntityManager(); 47 | var entity = em.CreateEntity(); 48 | var producer = CreateWidgetFactory(); 49 | entity.AddComponent(producer); 50 | 51 | var inventory = new Inventory(); 52 | inventory.Size = 10; 53 | entity.AddComponent( inventory); 54 | 55 | var productionSystem = new ProductionSystem(_mockEngine); 56 | productionSystem.Run(entity); 57 | Assert.AreEqual(10, inventory.Items.Count); 58 | } 59 | 60 | [Test] 61 | public void ProducedItemNameTest() 62 | { 63 | var em = new EntityManager(); 64 | var entity = em.CreateEntity(); 65 | var producer = CreateWidgetFactory(); 66 | entity.AddComponent( producer); 67 | var inventory = new Inventory(); 68 | inventory.Size = 10; 69 | entity.AddComponent( inventory); 70 | var productionSystem = new ProductionSystem(_mockEngine); 71 | productionSystem.Run(entity); 72 | 73 | var item = inventory.Items[0]; 74 | var name = item.GetComponent().Type; 75 | Assert.AreEqual(name, producer.ProducedItems[0].product); 76 | } 77 | 78 | [Test] 79 | public void DemandTest() 80 | { 81 | var em = new EntityManager(); 82 | var entity = em.CreateEntity(); 83 | var producer = CreateWidgetFactory(); 84 | entity.AddComponent(producer); 85 | var inventory = new Inventory(); 86 | inventory.Size = 10; 87 | entity.AddComponent( inventory); 88 | var productionSystem = new ProductionSystem(_mockEngine); 89 | productionSystem.Run(entity); 90 | 91 | var demand = new Demand(); 92 | demand.Demands.Add("widget", 1); 93 | entity.AddComponent( demand); 94 | var demandSystem = new DemandSystem(_mockEngine); 95 | demandSystem.Run(entity); 96 | 97 | Assert.Less(inventory.Items.Count, 10); 98 | } 99 | 100 | [Test] 101 | public void StackSystemTest() 102 | { 103 | var em = new EntityManager(); 104 | var entity = em.CreateEntity(); 105 | var inventory = new Inventory(); 106 | entity.AddComponent(inventory); 107 | var itemEntity = em.CreateEntity(); 108 | var itemComponent = new Item(){Type = "widget"}; 109 | itemEntity.AddComponent(); 110 | itemEntity.AddComponent(itemComponent); 111 | inventory.Items.Add(itemEntity); 112 | 113 | itemEntity = em.CreateEntity(); 114 | itemEntity.AddComponent(itemComponent); 115 | itemEntity.AddComponent(); 116 | inventory.Items.Add(itemEntity); 117 | 118 | var stackSystem = new StackSystem(_mockEngine); 119 | var stacks = stackSystem.GetStacks(entity); 120 | 121 | Assert.AreEqual(2, stacks["widget"]); 122 | } 123 | 124 | // * //////////////// Helpers ///////////////// 125 | Producer CreateWidgetFactory() 126 | { 127 | var producer = new Producer(); 128 | var item = new Producer.ProductionItem(){product = "widget", rate = 11}; 129 | producer.ProducedItems.Add(item); 130 | return producer; 131 | } 132 | 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /EntityPrototypes.json: -------------------------------------------------------------------------------- 1 | { 2 | "Giant Ant": { 3 | "Actor": { 4 | "Speed": 9.5, 5 | "Gold": 0, 6 | "Energy": 0.0 7 | }, 8 | "AttackStat": { 9 | "Power": 2, 10 | "Accuracy": 50 11 | }, 12 | "DefenseStat": { 13 | "Chance": 5 14 | }, 15 | "Life": { 16 | "Health": 10, 17 | "MaxHealth": 10 18 | }, 19 | "Name": { 20 | "NameString": "Giant Ant" 21 | }, 22 | "Glyph": { 23 | "glyph": 0 24 | }, 25 | "Faction": { 26 | "Type": 2 27 | }, 28 | "WanderingMonster": {} 29 | }, 30 | "Goblin": { 31 | "Actor": { 32 | "Speed": 8.0, 33 | "Gold": 0, 34 | "Energy": 0.0 35 | }, 36 | "AttackStat": { 37 | "Power": 2, 38 | "Accuracy": 50 39 | }, 40 | "DefenseStat": { 41 | "Chance": 1 42 | }, 43 | "Life": { 44 | "Health": 5, 45 | "MaxHealth": 5 46 | }, 47 | "Name": { 48 | "NameString": "Goblin" 49 | }, 50 | "Glyph": { 51 | "glyph": 71 52 | }, 53 | "Faction": { 54 | "Type": 2 55 | }, 56 | "WanderingMonster": {} 57 | }, 58 | "Kobold": { 59 | "Actor": { 60 | "Speed": 8.0, 61 | "Gold": 0, 62 | "Energy": 0.0 63 | }, 64 | "AttackStat": { 65 | "Power": 1, 66 | "Accuracy": 70 67 | }, 68 | "DefenseStat": { 69 | "Chance": 1 70 | }, 71 | "Life": { 72 | "Health": 1, 73 | "MaxHealth": 1 74 | }, 75 | "Name": { 76 | "NameString": "Kobold" 77 | }, 78 | "Glyph": { 79 | "glyph": 60 80 | }, 81 | "Faction": { 82 | "Type": 2 83 | }, 84 | "WanderingMonster": {} 85 | } 86 | } -------------------------------------------------------------------------------- /FeatureDetector/DetectorTests.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using NUnit.Framework; 3 | 4 | namespace FeatureDetector 5 | { 6 | [TestFixture] 7 | public class DetectorTests 8 | { 9 | [Test] 10 | public void ConstructorTest() 11 | { 12 | var detector = new MapFeatureDetector(mapIntArray); 13 | } 14 | 15 | [Test] 16 | public void FindWallsTest() 17 | { 18 | var detector = new MapFeatureDetector(mapIntArray); 19 | var walls = detector.FindWalls(); 20 | Debug.WriteLine(detector.ToMapString(walls)); 21 | Assert.AreEqual(1, walls[12,45]); 22 | Assert.AreEqual(1, walls[12,27]); 23 | Assert.AreEqual(1, walls[13,27]); 24 | Assert.AreEqual(1, walls[14,27]); 25 | Assert.AreEqual(1, walls[20,34]); 26 | Assert.AreEqual(1, walls[8,30]); 27 | Assert.AreEqual(1, walls[8,31]); 28 | Assert.AreEqual(1, walls[8,32]); 29 | Assert.AreEqual(1, walls[8,33]); 30 | Assert.AreEqual(1, walls[8,34]); 31 | Assert.AreEqual(1, walls[8,35]); 32 | } 33 | 34 | 35 | [Test] 36 | public void FindDoorwaysTest() 37 | { 38 | var detector = new MapFeatureDetector(mapIntArray); 39 | var doorways = detector.FindDoorways(); 40 | Debug.WriteLine(detector.ToMapString(doorways)); 41 | 42 | Assert.AreEqual(2, doorways[19, 21]); 43 | Assert.AreEqual(3, doorways[29, 28]); 44 | Assert.AreEqual(4, doorways[34, 24]); 45 | Assert.AreEqual(0, doorways[23, 43]); 46 | } 47 | 48 | [Test] 49 | public void Temp() 50 | { 51 | var detector = new MapFeatureDetector(mapIntArray); 52 | var conv = MapFeatureDetector.ConvolveFilter(mapIntArray, FeatureFilters.NeighborCount); 53 | IterateMaps(detector, conv); 54 | } 55 | 56 | [Test] 57 | public void GetApproximateRoomCenter() 58 | { 59 | var regions = MapFeatureDetector.GetRegions(mapIntArray); 60 | var approxCenter = MapFeatureDetector.GetApproximateRoomCenter(regions, 2); 61 | } 62 | 63 | private static void IterateMaps(MapFeatureDetector detector, int[,] conv) 64 | { 65 | var min = conv.Min(); 66 | var max = conv.Max(); 67 | for (int i = min; i <= max; i++) 68 | { 69 | var splats = detector.FilterArray(conv, i); 70 | if(splats.Total() > 0) 71 | { 72 | Debug.WriteLine(i); 73 | Debug.WriteLine(detector.ToMapString(splats)); 74 | } 75 | } 76 | } 77 | 78 | 79 | [Test] 80 | public void FloodFillTest() 81 | { 82 | var testArray = (int[,]) mapIntArray.Clone(); 83 | MapFeatureDetector.AdamMilFill(testArray, 10, 9); 84 | Assert.AreEqual(1, testArray[10, 9]); 85 | } 86 | 87 | [Test] 88 | public void RegionTest() 89 | { 90 | var regionArray = MapFeatureDetector.GetRegions(mapIntArray); 91 | Debug.WriteLine(regionArray.ToRowString(asMap: true)); 92 | Assert.AreEqual(3, regionArray[12,9]); 93 | Assert.AreEqual(4, regionArray[27,14]); 94 | Assert.AreEqual(2, regionArray[23,56]); 95 | } 96 | 97 | 98 | int[,] mapIntArray = new int[,]{ 99 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 100 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 101 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 102 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 103 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 104 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 105 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 106 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 107 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 108 | {1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 109 | {1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 110 | {1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 111 | {1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 112 | {1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 113 | {1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 114 | {1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 115 | {1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 116 | {1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 117 | {1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 118 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 119 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1}, 120 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1}, 121 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 122 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, 123 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1}, 124 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1}, 125 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1}, 126 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1}, 127 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1}, 128 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1}, 129 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1}, 130 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1}, 131 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1}, 132 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1}, 133 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1}, 134 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1}, 135 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 136 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 137 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, 138 | {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}}; 139 | 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /FeatureDetector/FeatureDetector.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard20;net461 5 | $(SolutionDir)\bin\$(Configuration)\$(AssemblyName)\ 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /FeatureDetector/FeatureFilters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace FeatureDetector 7 | { 8 | public static class FeatureFilters 9 | { 10 | // 1 == impassable/wall 11 | public static int[,] Vertical = new int[,]{ 12 | {-1, 4,-1}, 13 | {-1, 4,-1}, 14 | {-1, 4,-1} 15 | }; 16 | 17 | public static int[,] Doorway = new int[,]{ 18 | { -2,-16,-2}, 19 | { 2,-16, 2}, 20 | { 2,-16, 2}, 21 | }; 22 | 23 | public static int[,] OuterCorner = new int[,]{ 24 | { 0,-32,-32}, 25 | { 8, 8,-32}, 26 | { 8, 8, 0}, 27 | }; 28 | 29 | public static int[,] InnerCorner = new int[,]{ 30 | { 4, 4,-8}, 31 | { 4, 4, 4}, 32 | { 4, 4, 4}, 33 | }; 34 | 35 | public static int[,] NeighborCount = new int[,]{ 36 | { 1, 1, 1}, 37 | { 1, 0, 1}, 38 | { 1, 1, 1}, 39 | }; 40 | 41 | public static int[,] Identity = new int[,]{ 42 | {0,0,0}, 43 | {0,1,0}, 44 | {0,0,0} 45 | }; 46 | 47 | public static int[,] Rotate180Degrees(int[,] oldMatrix) 48 | { 49 | int[,] newMatrix = Rotate90CCW(oldMatrix); 50 | newMatrix = Rotate90CCW(newMatrix); 51 | return newMatrix; 52 | } 53 | 54 | public static int[,] Rotate90CCW(int[,] oldMatrix) 55 | { 56 | int[,] newMatrix = new int[oldMatrix.GetLength(1), oldMatrix.GetLength(0)]; 57 | int newColumn, newRow = 0; 58 | for (int oldColumn = oldMatrix.GetLength(1) - 1; oldColumn >= 0; oldColumn--) 59 | { 60 | newColumn = 0; 61 | for (int oldRow = 0; oldRow < oldMatrix.GetLength(0); oldRow++) 62 | { 63 | newMatrix[newRow, newColumn] = oldMatrix[oldRow, oldColumn]; 64 | newColumn++; 65 | } 66 | newRow++; 67 | } 68 | return newMatrix; 69 | } 70 | 71 | /// 72 | /// Matrix multiply two int[] 73 | /// 74 | /// 75 | /// 76 | /// Matrix of multiplied values 77 | public static int[] MultiplyFilter(int[] sample, int[] filter) 78 | { 79 | if (sample.Length != filter.Length) 80 | { 81 | throw new ArgumentException("sample and filter must be the same size."); 82 | } 83 | var outArray = new int[filter.Length]; 84 | for (int i = 0; i < filter.Length; i++) 85 | { 86 | outArray[i] = sample[i] * filter[i]; 87 | } 88 | return outArray; 89 | } 90 | 91 | public static string ToFilterString(int[,] filter) 92 | { 93 | var sb = new StringBuilder(); 94 | for (int i = 0; i < filter.GetLength(0); i++) 95 | { 96 | for (int j = 0; j < filter.GetLength(1); j++) 97 | { 98 | sb.Append($"{filter[i, j]:##}"); 99 | } 100 | sb.AppendLine(); 101 | } 102 | return sb.ToString(); 103 | } 104 | } 105 | 106 | public static class GridExtentsions 107 | { 108 | public static void UpDate(this int[,] grid, Func action) 109 | { 110 | if (grid.Rank != 2) 111 | { 112 | throw new NotImplementedException("Only valid on 2D arrays."); 113 | } 114 | 115 | for (int i = 0; i < grid.GetLength(0); i++) 116 | { 117 | for (int j = 0; j < grid.GetLength(1); j++) 118 | { 119 | grid[i, j] = action(grid[i, j]); 120 | } 121 | } 122 | } 123 | 124 | 125 | /// 126 | /// Total the array elements 127 | /// 128 | /// 129 | /// 130 | public static int Total(this int[] array) 131 | { 132 | var total = 0; 133 | for (int i = 0; i < array.Length; i++) 134 | { 135 | total += array[i]; 136 | } 137 | return total; 138 | } 139 | 140 | /// 141 | /// Total the array elements 142 | /// 143 | /// 144 | /// 145 | public static int Total(this int[,] array) 146 | { 147 | var total = 0; 148 | for (int i = 0; i < array.GetLength(0); i++) 149 | { 150 | for (int j = 0; j < array.GetLength(1); j++) 151 | { 152 | total += array[i, j]; 153 | } 154 | } 155 | return total; 156 | } 157 | 158 | public static int Min(this int[,] array) 159 | { 160 | var min = int.MaxValue; 161 | for (int i = 0; i < array.GetLength(0); i++) 162 | { 163 | for (int j = 0; j < array.GetLength(1); j++) 164 | { 165 | min = Math.Min(array[i, j], min); 166 | } 167 | } 168 | return min; 169 | } 170 | 171 | public static int Max(this int[,] array) 172 | { 173 | var max = int.MinValue; 174 | for (int i = 0; i < array.GetLength(0); i++) 175 | { 176 | for (int j = 0; j < array.GetLength(1); j++) 177 | { 178 | max = Math.Max(array[i, j], max); 179 | } 180 | } 181 | return max; 182 | } 183 | 184 | public static int[] UniqueValues (this int[,] array) 185 | { 186 | var flat = array.Flatten(); 187 | var hashSet = new HashSet(); 188 | foreach(var v in flat) 189 | { 190 | hashSet.Add(v); 191 | } 192 | return hashSet.ToArray(); 193 | } 194 | 195 | /// 196 | /// Pointwise multiply two int[,] arrays 197 | /// 198 | /// 199 | /// 200 | /// 201 | public static int[,] Multiply(this int[,] a, int[,] b) 202 | { 203 | // TODO: Check arrays are same shape. 204 | var outArr = (int[,]) a.Clone(); 205 | for (int x = 0; x < a.GetLength(0); x++) 206 | { 207 | for (int y = 0; y < a.GetLength(1); y++) 208 | { 209 | outArr[x,y] = a[x,y] * b[x,y]; 210 | } 211 | 212 | } 213 | return outArr; 214 | } 215 | 216 | public static byte[] FlattenToByteArray(this int[,] sample) 217 | { 218 | var width = sample.GetLength(0); 219 | var height = sample.GetLength(1); 220 | byte[] flat = new byte[width * height]; 221 | for (int i = 0; i < width; i++) 222 | { 223 | for (int j = 0; j < height; j++) 224 | { 225 | if(sample[i,j] > byte.MaxValue || sample[i,j] < byte.MinValue) 226 | { 227 | throw new IndexOutOfRangeException($"[{i},{j}] == '{sample[i,j]}' out of range for byte conversion"); 228 | } 229 | flat[i + (j * width)] = (byte)sample[i, j]; 230 | } 231 | } 232 | return flat; 233 | } 234 | public static int[] Flatten(this int[,] sample) 235 | { 236 | var width = sample.GetLength(0); 237 | var height = sample.GetLength(1); 238 | int[] flat = new int[width * height]; 239 | for (int i = 0; i < width; i++) 240 | { 241 | for (int j = 0; j < height; j++) 242 | { 243 | flat[i + (j * width)] = sample[i, j]; 244 | } 245 | } 246 | return flat; 247 | } 248 | 249 | public static string ToRowString(this int[,] sample, bool asMap = false) 250 | { 251 | var rows = sample.GetLength(1); 252 | var flat = sample.Flatten(); 253 | return flat.ToRowString(rows, asMap); 254 | } 255 | 256 | /// 257 | /// Returns an array as a grid of numRows 258 | /// 259 | /// 260 | /// 261 | /// String representation 262 | public static string ToRowString(this int[] sample, int numRows, bool asMap = false) 263 | { 264 | var sb = new StringBuilder(); 265 | var perRow = sample.Length / numRows; 266 | for (int i = 0; i < sample.Length; i++) 267 | { 268 | var output = sample[i].ToString(); 269 | if (asMap) 270 | { 271 | output = sample[i] == 0 ? "." : "#"; 272 | if (sample[i] > 1) 273 | { 274 | output = sample[i].ToString(); 275 | } 276 | } 277 | 278 | sb.Append(output); 279 | if (i < sample.Length - 1 && !asMap) 280 | { 281 | sb.Append(", "); 282 | } 283 | if ((i + 1) % perRow == 0) 284 | { 285 | sb.AppendLine(); 286 | } 287 | } 288 | sb.AppendLine(); 289 | return sb.ToString(); 290 | } 291 | } 292 | } -------------------------------------------------------------------------------- /InventionHackGameplay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionHackGameplay.gif -------------------------------------------------------------------------------- /InventionUiAndroid/InventionUiAndroid.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {7FA2F095-811B-4018-8C3A-8A0E8E1453D5} 9 | {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10 | {122416d6-6b49-4ee2-a1e8-b825f31c79fe} 11 | Library 12 | Properties 13 | InventionUiAndroid 14 | InventionUiAndroid 15 | 512 16 | True 17 | Resources\Resource.designer.cs 18 | Resource 19 | Off 20 | false 21 | v9.0 22 | Properties\AndroidManifest.xml 23 | Resources 24 | Assets 25 | true 26 | true 27 | Xamarin.Android.Net.AndroidClientHandler 28 | 29 | 30 | True 31 | portable 32 | False 33 | bin\Debug\ 34 | DEBUG;TRACE 35 | prompt 36 | 4 37 | True 38 | None 39 | False 40 | 41 | 42 | True 43 | portable 44 | True 45 | bin\Release\ 46 | TRACE 47 | prompt 48 | 4 49 | true 50 | False 51 | SdkOnly 52 | True 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | Assets\tiledata.json 70 | 71 | 72 | 73 | 74 | 75 | Designer 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 1.0.50 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | {5c3415f8-c59a-4c93-85fb-c373cbff34fe} 114 | Portable 115 | 116 | 117 | 118 | 119 | Assets\absurd64.bmp 120 | 121 | 122 | 123 | 130 | -------------------------------------------------------------------------------- /InventionUiAndroid/MainActivity.cs: -------------------------------------------------------------------------------- 1 | namespace InventionUiAndroid 2 | { 3 | [Android.App.Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true, ConfigurationChanges = Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)] 4 | public class MainActivity : Inv.AndroidActivity 5 | { 6 | protected override void Install(Inv.Application Application) 7 | { 8 | Portable.Shell.Install(Application); 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /InventionUiAndroid/Properties/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /InventionUiAndroid/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using Android.App; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("InventionUiAndroid")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("InventionUiAndroid")] 14 | [assembly: AssemblyCopyright("Copyright © 2018")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: ComVisible(false)] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("1.0.0.0")] 30 | [assembly: AssemblyFileVersion("1.0.0.0")] 31 | -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiAndroid/Resources/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #2c3e50 4 | #1B3147 5 | #3498db 6 | 7 | -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #2C3E50 4 | -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | InventionUiAndroid 3 | Settings 4 | 5 | -------------------------------------------------------------------------------- /InventionUiAndroid/Resources/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /InventionUiUwp/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | -------------------------------------------------------------------------------- /InventionUiUwp/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.ApplicationModel; 7 | using Windows.ApplicationModel.Activation; 8 | using Windows.Foundation; 9 | using Windows.Foundation.Collections; 10 | using Windows.UI.Xaml; 11 | using Windows.UI.Xaml.Controls; 12 | using Windows.UI.Xaml.Controls.Primitives; 13 | using Windows.UI.Xaml.Data; 14 | using Windows.UI.Xaml.Input; 15 | using Windows.UI.Xaml.Media; 16 | using Windows.UI.Xaml.Navigation; 17 | 18 | namespace InventionUiUwp 19 | { 20 | /// 21 | /// Provides application-specific behavior to supplement the default Application class. 22 | /// 23 | sealed partial class App : Application 24 | { 25 | /// 26 | /// Initializes the singleton application object. This is the first line of authored code 27 | /// executed, and as such is the logical equivalent of main() or WinMain(). 28 | /// 29 | public App() 30 | { 31 | this.InitializeComponent(); 32 | this.Suspending += OnSuspending; 33 | } 34 | 35 | /// 36 | /// Invoked when the application is launched normally by the end user. Other entry points 37 | /// will be used such as when the application is launched to open a specific file. 38 | /// 39 | /// Details about the launch request and process. 40 | protected override void OnLaunched(LaunchActivatedEventArgs e) 41 | { 42 | Frame rootFrame = Window.Current.Content as Frame; 43 | 44 | // Do not repeat app initialization when the Window already has content, 45 | // just ensure that the window is active 46 | if (rootFrame == null) 47 | { 48 | // Create a Frame to act as the navigation context and navigate to the first page 49 | rootFrame = new Frame(); 50 | 51 | rootFrame.NavigationFailed += OnNavigationFailed; 52 | 53 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) 54 | { 55 | //TODO: Load state from previously suspended application 56 | } 57 | 58 | // Place the frame in the current Window 59 | Window.Current.Content = rootFrame; 60 | } 61 | 62 | if (e.PrelaunchActivated == false) 63 | { 64 | if (rootFrame.Content == null) 65 | { 66 | // When the navigation stack isn't restored navigate to the first page, 67 | // configuring the new page by passing required information as a navigation 68 | // parameter 69 | rootFrame.Navigate(typeof(MainPage), e.Arguments); 70 | } 71 | // Ensure the current window is active 72 | Window.Current.Activate(); 73 | } 74 | } 75 | 76 | /// 77 | /// Invoked when Navigation to a certain page fails 78 | /// 79 | /// The Frame which failed navigation 80 | /// Details about the navigation failure 81 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e) 82 | { 83 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName); 84 | } 85 | 86 | /// 87 | /// Invoked when application execution is being suspended. Application state is saved 88 | /// without knowing whether the application will be terminated or resumed with the contents 89 | /// of memory still intact. 90 | /// 91 | /// The source of the suspend request. 92 | /// Details about the suspend request. 93 | private void OnSuspending(object sender, SuspendingEventArgs e) 94 | { 95 | var deferral = e.SuspendingOperation.GetDeferral(); 96 | //TODO: Save application state and stop any background activity 97 | deferral.Complete(); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /InventionUiUwp/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiUwp/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /InventionUiUwp/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiUwp/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /InventionUiUwp/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiUwp/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /InventionUiUwp/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiUwp/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /InventionUiUwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiUwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /InventionUiUwp/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiUwp/Assets/StoreLogo.png -------------------------------------------------------------------------------- /InventionUiUwp/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiUwp/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /InventionUiUwp/InventionUiUwp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x86 7 | {268B3734-8A91-42E7-B475-F429B924EE94} 8 | AppContainerExe 9 | Properties 10 | InventionUiUwp 11 | InventionUiUwp 12 | en-US 13 | UAP 14 | 10.0.18362.0 15 | 10.0.16299.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | true 20 | false 21 | 22 | 23 | true 24 | bin\x86\Debug\ 25 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 26 | ;2008 27 | full 28 | x86 29 | false 30 | prompt 31 | true 32 | 33 | 34 | bin\x86\Release\ 35 | TRACE;NETFX_CORE;WINDOWS_UWP 36 | true 37 | ;2008 38 | pdbonly 39 | x86 40 | false 41 | prompt 42 | true 43 | true 44 | 45 | 46 | true 47 | bin\ARM\Debug\ 48 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 49 | ;2008 50 | full 51 | ARM 52 | false 53 | prompt 54 | true 55 | 56 | 57 | bin\ARM\Release\ 58 | TRACE;NETFX_CORE;WINDOWS_UWP 59 | true 60 | ;2008 61 | pdbonly 62 | ARM 63 | false 64 | prompt 65 | true 66 | true 67 | 68 | 69 | true 70 | bin\ARM64\Debug\ 71 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 72 | ;2008 73 | full 74 | ARM64 75 | false 76 | prompt 77 | true 78 | true 79 | 80 | 81 | bin\ARM64\Release\ 82 | TRACE;NETFX_CORE;WINDOWS_UWP 83 | true 84 | ;2008 85 | pdbonly 86 | ARM64 87 | false 88 | prompt 89 | true 90 | true 91 | 92 | 93 | true 94 | bin\x64\Debug\ 95 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 96 | ;2008 97 | full 98 | x64 99 | false 100 | prompt 101 | true 102 | 103 | 104 | bin\x64\Release\ 105 | TRACE;NETFX_CORE;WINDOWS_UWP 106 | true 107 | ;2008 108 | pdbonly 109 | x64 110 | false 111 | prompt 112 | true 113 | true 114 | 115 | 116 | PackageReference 117 | 118 | 119 | 120 | App.xaml 121 | 122 | 123 | MainPage.xaml 124 | 125 | 126 | 127 | 128 | 129 | Designer 130 | 131 | 132 | 133 | 134 | Assets\absurd64.bmp 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | MSBuild:Compile 148 | Designer 149 | 150 | 151 | MSBuild:Compile 152 | Designer 153 | 154 | 155 | 156 | 157 | 1.0.50 158 | 159 | 160 | 6.2.9 161 | 162 | 163 | 164 | 165 | {5c3415f8-c59a-4c93-85fb-c373cbff34fe} 166 | Portable 167 | 168 | 169 | 170 | 171 | Assets\tiledata.json 172 | 173 | 174 | 175 | 14.0 176 | 177 | 178 | 185 | -------------------------------------------------------------------------------- /InventionUiUwp/MainPage.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /InventionUiUwp/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 2 | 3 | namespace InventionUiUwp 4 | { 5 | /// 6 | /// An empty page that can be used on its own or navigated to within a Frame. 7 | /// 8 | public sealed partial class MainPage : Windows.UI.Xaml.Controls.Page 9 | { 10 | public MainPage() 11 | { 12 | this.InitializeComponent(); 13 | 14 | Inv.UwaShell.Attach(this, Portable.Shell.Install); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /InventionUiUwp/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | InventionUiUwp 18 | callanh 19 | Assets\StoreLogo.png 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /InventionUiUwp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("InventionUiUwp")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("InventionUiUwp")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /InventionUiUwp/Properties/Default.rd.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /InventionUiWpf/InventionUiWpf.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net461 6 | true 7 | $(SolutionDir)\bin\$(Configuration)\$(AssemblyName)\ 8 | x64 9 | portable 10 | 11 | 12 | 13 | 14 | PreserveNewest 15 | 16 | 17 | PreserveNewest 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /InventionUiWpf/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace InventionUiWpf 4 | { 5 | public class Program 6 | { 7 | [STAThread] 8 | static void Main(string[] args) 9 | { 10 | Inv.WpfShell.CheckRequirements( 11 | () => 12 | { 13 | // #if DEBUG 14 | // Inv.WpfShell.Options.PreventDeviceEmulation = false; 15 | // Inv.WpfShell.Options.DeviceEmulation = Inv.WpfDeviceEmulation.iPad_Mini; 16 | // #endif 17 | Inv.WpfShell.Options.FullScreenMode = false; 18 | Inv.WpfShell.Options.DefaultWindowWidth = 800; 19 | Inv.WpfShell.Options.DefaultWindowHeight = 600; 20 | Inv.WpfShell.Run(Portable.Shell.Install); 21 | }); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /InventionUiWpf/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /InventionUiiOS/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using Foundation; 2 | using UIKit; 3 | 4 | namespace InventionUiiOS 5 | { 6 | // The UIApplicationDelegate for the application. This class is responsible for launching the 7 | // User Interface of the application, as well as listening (and optionally responding) to application events from iOS. 8 | [Register("AppDelegate")] 9 | public class AppDelegate : UIApplicationDelegate 10 | { 11 | // class-level declarations 12 | 13 | public override UIWindow Window 14 | { 15 | get; 16 | set; 17 | } 18 | 19 | public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) 20 | { 21 | // create a new window instance based on the screen size 22 | Window = new UIWindow(UIScreen.MainScreen.Bounds); 23 | Window.RootViewController = new UIViewController(); 24 | 25 | // make the window visible 26 | Window.MakeKeyAndVisible(); 27 | 28 | return true; 29 | } 30 | 31 | public override void OnResignActivation(UIApplication application) 32 | { 33 | // Invoked when the application is about to move from active to inactive state. 34 | // This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) 35 | // or when the user quits the application and it begins the transition to the background state. 36 | // Games should use this method to pause the game. 37 | } 38 | 39 | public override void DidEnterBackground(UIApplication application) 40 | { 41 | // Use this method to release shared resources, save user data, invalidate timers and store the application state. 42 | // If your application supports background execution this method is called instead of WillTerminate when the user quits. 43 | } 44 | 45 | public override void WillEnterForeground(UIApplication application) 46 | { 47 | // Called as part of the transition from background to active state. 48 | // Here you can undo many of the changes made on entering the background. 49 | } 50 | 51 | public override void OnActivated(UIApplication application) 52 | { 53 | // Restart any tasks that were paused (or not yet started) while the application was inactive. 54 | // If the application was previously in the background, optionally refresh the user interface. 55 | } 56 | 57 | public override void WillTerminate(UIApplication application) 58 | { 59 | // Called when the application is about to terminate. Save data, if needed. See also DidEnterBackground. 60 | } 61 | } 62 | } 63 | 64 | 65 | -------------------------------------------------------------------------------- /InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "scale": "2x", 5 | "size": "20x20", 6 | "idiom": "iphone", 7 | "filename": "Icon40.png" 8 | }, 9 | { 10 | "scale": "3x", 11 | "size": "20x20", 12 | "idiom": "iphone", 13 | "filename": "Icon60.png" 14 | }, 15 | { 16 | "scale": "2x", 17 | "size": "29x29", 18 | "idiom": "iphone", 19 | "filename": "Icon58.png" 20 | }, 21 | { 22 | "scale": "3x", 23 | "size": "29x29", 24 | "idiom": "iphone", 25 | "filename": "Icon87.png" 26 | }, 27 | { 28 | "scale": "2x", 29 | "size": "40x40", 30 | "idiom": "iphone", 31 | "filename": "Icon80.png" 32 | }, 33 | { 34 | "scale": "3x", 35 | "size": "40x40", 36 | "idiom": "iphone", 37 | "filename": "Icon120.png" 38 | }, 39 | { 40 | "scale": "2x", 41 | "size": "60x60", 42 | "idiom": "iphone", 43 | "filename": "Icon120.png" 44 | }, 45 | { 46 | "scale": "3x", 47 | "size": "60x60", 48 | "idiom": "iphone", 49 | "filename": "Icon180.png" 50 | }, 51 | { 52 | "scale": "1x", 53 | "size": "20x20", 54 | "idiom": "ipad", 55 | "filename": "Icon20.png" 56 | }, 57 | { 58 | "scale": "2x", 59 | "size": "20x20", 60 | "idiom": "ipad", 61 | "filename": "Icon40.png" 62 | }, 63 | { 64 | "scale": "1x", 65 | "size": "29x29", 66 | "idiom": "ipad", 67 | "filename": "Icon29.png" 68 | }, 69 | { 70 | "scale": "2x", 71 | "size": "29x29", 72 | "idiom": "ipad", 73 | "filename": "Icon58.png" 74 | }, 75 | { 76 | "scale": "1x", 77 | "size": "40x40", 78 | "idiom": "ipad", 79 | "filename": "Icon40.png" 80 | }, 81 | { 82 | "scale": "2x", 83 | "size": "40x40", 84 | "idiom": "ipad", 85 | "filename": "Icon80.png" 86 | }, 87 | { 88 | "scale": "1x", 89 | "size": "76x76", 90 | "idiom": "ipad", 91 | "filename": "Icon76.png" 92 | }, 93 | { 94 | "scale": "2x", 95 | "size": "76x76", 96 | "idiom": "ipad", 97 | "filename": "Icon152.png" 98 | }, 99 | { 100 | "scale": "2x", 101 | "size": "83.5x83.5", 102 | "idiom": "ipad", 103 | "filename": "Icon167.png" 104 | }, 105 | { 106 | "scale": "1x", 107 | "size": "1024x1024", 108 | "idiom": "ios-marketing", 109 | "filename": "Icon1024.png" 110 | } 111 | ], 112 | "properties": {}, 113 | "info": { 114 | "version": 1, 115 | "author": "xcode" 116 | } 117 | } -------------------------------------------------------------------------------- /InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png -------------------------------------------------------------------------------- /InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon120.png -------------------------------------------------------------------------------- /InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon152.png -------------------------------------------------------------------------------- /InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon167.png -------------------------------------------------------------------------------- /InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon180.png -------------------------------------------------------------------------------- /InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon20.png -------------------------------------------------------------------------------- /InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon29.png -------------------------------------------------------------------------------- /InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon40.png -------------------------------------------------------------------------------- /InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon58.png -------------------------------------------------------------------------------- /InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon60.png -------------------------------------------------------------------------------- /InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon76.png -------------------------------------------------------------------------------- /InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon80.png -------------------------------------------------------------------------------- /InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/InventionUiiOS/Assets.xcassets/AppIcon.appiconset/Icon87.png -------------------------------------------------------------------------------- /InventionUiiOS/Entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /InventionUiiOS/Info.plist: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | CFBundleDisplayName 6 | InventionUiiOS 7 | CFBundleIdentifier 8 | com.companyname.InventionUiiOS 9 | CFBundleShortVersionString 10 | 1.0 11 | CFBundleVersion 12 | 1.0 13 | LSRequiresIPhoneOS 14 | 15 | MinimumOSVersion 16 | 8.0 17 | UIDeviceFamily 18 | 19 | 1 20 | 2 21 | 22 | UILaunchStoryboardName 23 | LaunchScreen 24 | UIRequiredDeviceCapabilities 25 | 26 | armv7 27 | 28 | UISupportedInterfaceOrientations 29 | 30 | UIInterfaceOrientationPortrait 31 | UIInterfaceOrientationLandscapeLeft 32 | UIInterfaceOrientationLandscapeRight 33 | 34 | UISupportedInterfaceOrientations~ipad 35 | 36 | UIInterfaceOrientationPortrait 37 | UIInterfaceOrientationPortraitUpsideDown 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | XSAppIconAssets 42 | Assets.xcassets/AppIcon.appiconset 43 | 44 | -------------------------------------------------------------------------------- /InventionUiiOS/InventionUiiOS.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | iPhoneSimulator 6 | {F162B517-8CA6-43CA-A86C-611E6027AAE8} 7 | {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 8 | {440aa056-593a-4519-8708-27081dee632f} 9 | Exe 10 | InventionUiiOS 11 | Resources 12 | InventionUiiOS 13 | true 14 | NSUrlSessionHandler 15 | PackageReference 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\iPhoneSimulator\Debug 22 | DEBUG 23 | prompt 24 | 4 25 | x86_64 26 | None 27 | true 28 | true 29 | 30 | 31 | none 32 | true 33 | bin\iPhoneSimulator\Release 34 | prompt 35 | 4 36 | None 37 | x86_64 38 | 39 | 40 | true 41 | full 42 | false 43 | bin\iPhone\Debug 44 | DEBUG 45 | prompt 46 | 4 47 | ARM64 48 | Entitlements.plist 49 | iPhone Developer 50 | true 51 | 52 | 53 | none 54 | true 55 | bin\iPhone\Release 56 | prompt 57 | 4 58 | Entitlements.plist 59 | ARM64 60 | iPhone Developer 61 | 62 | 63 | 64 | 65 | 66 | Resources\tiledata.json 67 | 68 | 69 | 70 | 71 | Resources\absurd64.bmp 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 1.0.50 87 | 88 | 89 | 90 | 91 | 92 | false 93 | 94 | 95 | false 96 | 97 | 98 | false 99 | 100 | 101 | false 102 | 103 | 104 | false 105 | 106 | 107 | false 108 | 109 | 110 | false 111 | 112 | 113 | false 114 | 115 | 116 | false 117 | 118 | 119 | false 120 | 121 | 122 | false 123 | 124 | 125 | false 126 | 127 | 128 | false 129 | 130 | 131 | false 132 | 133 | 134 | 135 | 136 | 137 | {5c3415f8-c59a-4c93-85fb-c373cbff34fe} 138 | Portable 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /InventionUiiOS/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /InventionUiiOS/Main.cs: -------------------------------------------------------------------------------- 1 | using UIKit; 2 | 3 | namespace InventionUiiOS 4 | { 5 | public class Application 6 | { 7 | // This is the main entry point of the application. 8 | static void Main(string[] args) 9 | { 10 | Inv.iOSShell.Run(Portable.Shell.Install); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /InventionUiiOS/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("InventionUiiOS")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("InventionUiiOS")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("50c7b8c9-e664-45af-b88e-0c9b8b9c1be1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /InventionUiiOS/Resources/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 21 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /InventionUiiOS/SceneDelegate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Foundation; 3 | using UIKit; 4 | 5 | namespace NewSingleViewTemplate { 6 | [Register ("SceneDelegate")] 7 | public class SceneDelegate : UIResponder, IUIWindowSceneDelegate { 8 | 9 | [Export ("window")] 10 | public UIWindow Window { get; set; } 11 | 12 | [Export ("scene:willConnectToSession:options:")] 13 | public void WillConnect (UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions) 14 | { 15 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 16 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 17 | // This delegate does not imply the connecting scene or session are new (see UIApplicationDelegate `GetConfiguration` instead). 18 | } 19 | 20 | [Export ("sceneDidDisconnect:")] 21 | public void DidDisconnect (UIScene scene) 22 | { 23 | // Called as the scene is being released by the system. 24 | // This occurs shortly after the scene enters the background, or when its session is discarded. 25 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 26 | // The scene may re-connect later, as its session was not neccessarily discarded (see UIApplicationDelegate `DidDiscardSceneSessions` instead). 27 | } 28 | 29 | [Export ("sceneDidBecomeActive:")] 30 | public void DidBecomeActive (UIScene scene) 31 | { 32 | // Called when the scene has moved from an inactive state to an active state. 33 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 34 | } 35 | 36 | [Export ("sceneWillResignActive:")] 37 | public void WillResignActive (UIScene scene) 38 | { 39 | // Called when the scene will move from an active state to an inactive state. 40 | // This may occur due to temporary interruptions (ex. an incoming phone call). 41 | } 42 | 43 | [Export ("sceneWillEnterForeground:")] 44 | public void WillEnterForeground (UIScene scene) 45 | { 46 | // Called as the scene transitions from the background to the foreground. 47 | // Use this method to undo the changes made on entering the background. 48 | } 49 | 50 | [Export ("sceneDidEnterBackground:")] 51 | public void DidEnterBackground (UIScene scene) 52 | { 53 | // Called as the scene transitions from the foreground to the background. 54 | // Use this method to save data, release shared resources, and store enough scene-specific state information 55 | // to restore the scene back to its current state. 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Dustin Andrews 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Portable/Cloth.cs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Cloth class by Callan Hodgskin 2019, Modified by Dustin Andrews 2019 4 | Original code https://gitlab.com/snippets/1905512 5 | 6 | Example: 7 | var Cloth = new Cloth(); 8 | Cloth.Dimension = new Inv.Dimension(20, 20); 9 | Cloth.DrawEvent += (DC, Patch) => 10 | { 11 | if ((Patch.X % 2) == (Patch.Y % 2)) 12 | DC.DrawRectangle(Inv.Colour.DarkGray, null, 0, Patch.Rect); 13 | else 14 | DC.DrawRectangle(Inv.Colour.LightGray, null, 0, Patch.Rect); 15 | }; 16 | Cloth.Draw(); 17 | 18 | */ 19 | 20 | using System; 21 | 22 | namespace Inv 23 | { 24 | 25 | public class Patch 26 | { 27 | public int X; 28 | public int Y; 29 | public int CellX; 30 | public int CellY; 31 | public Rect Rect; 32 | 33 | } 34 | 35 | internal sealed class Cloth : Inv.Panel 36 | { 37 | public Cloth() 38 | { 39 | this.CellSizeProperty = 32; 40 | this.Patch = new Patch(); 41 | 42 | Base = Inv.Canvas.New(); 43 | Base.PressEvent += (Point) => 44 | { 45 | this.PanningPoint = Point; 46 | 47 | Base.Draw(); 48 | }; 49 | 50 | Base.AdjustEvent += () => 51 | { 52 | Base.Draw(); 53 | }; 54 | 55 | Base.MoveEvent += (Point) => 56 | { 57 | if (PanningPoint != null) 58 | { 59 | var DeltaPoint = PanningPoint.Value - Point; 60 | 61 | PanningX += DeltaPoint.X; 62 | PanningY += DeltaPoint.Y; 63 | 64 | this.PanningPoint = Point; 65 | 66 | Base.Draw(); 67 | } 68 | }; 69 | 70 | Base.ReleaseEvent += (Point) => 71 | { 72 | PanningPoint = null; 73 | 74 | Base.Draw(); 75 | }; 76 | 77 | Base.ZoomEvent += (Z) => 78 | { 79 | Zoom(Z.Point.X, Z.Point.Y, Z.Delta ); 80 | }; 81 | 82 | Base.DrawEvent += (DC) => 83 | { 84 | var CanvasDimension = Base.GetDimension(); 85 | var CanvasWidth = CanvasDimension.Width; 86 | var CanvasHeight = CanvasDimension.Height; 87 | var MapWidth = Dimension.Width * CellSizeProperty; 88 | var MapHeight = Dimension.Height * CellSizeProperty; 89 | var BufferX = Math.Max(300, CanvasWidth - MapWidth); 90 | var BufferY = Math.Max(300, CanvasHeight - MapHeight); 91 | 92 | if (InitialDraw) 93 | { 94 | this.InitialDraw = false; 95 | 96 | if (PanningX == 0 && PanningY == 0) 97 | { 98 | if (MapWidth < CanvasWidth) 99 | PanningX = (MapWidth - CanvasWidth) / 2; 100 | 101 | if (MapHeight < CanvasHeight) 102 | PanningY = (MapHeight - CanvasHeight) / 2; 103 | } 104 | } 105 | 106 | if (PanningX + CanvasWidth > MapWidth + BufferX) 107 | PanningX = MapWidth - CanvasWidth + BufferX; 108 | 109 | if (PanningX < -BufferX) 110 | PanningX = -BufferX; 111 | 112 | if (PanningY + CanvasHeight > MapHeight + BufferY) 113 | PanningY = MapHeight - CanvasHeight + BufferY; 114 | 115 | if (PanningY < -BufferY) 116 | PanningY = -BufferY; 117 | 118 | SetPanningParameters(); 119 | 120 | var CellY = -(PanningY % CellSizeProperty); 121 | 122 | for (var Y = PanningTop; Y <= PanningBottom; Y++) 123 | { 124 | var CellX = -(PanningX % CellSizeProperty); 125 | 126 | for (var X = PanningLeft; X <= PanningRight; X++) 127 | { 128 | if (X >= 0 && X < Dimension.Width && Y >= 0 && Y < Dimension.Height) 129 | { 130 | Patch.X = X; 131 | Patch.Y = Y; 132 | Patch.Rect = new Inv.Rect(CellX, CellY, CellSizeProperty, CellSizeProperty); 133 | 134 | DrawEvent?.Invoke(DC, Patch); 135 | } 136 | 137 | CellX += CellSizeProperty; 138 | } 139 | 140 | CellY += CellSizeProperty; 141 | } 142 | }; 143 | } 144 | 145 | public void Zoom(int X, int Y, int Delta) 146 | { 147 | var GlobalX = PanningX + X; 148 | var GlobalY = PanningY + Y; 149 | var OldX = GlobalX / CellSizeProperty; 150 | var OldY = GlobalY / CellSizeProperty; 151 | var ModX = GlobalX % CellSizeProperty; 152 | var ModY = GlobalY % CellSizeProperty; 153 | var smoothing = Math.Max(1, CellSize / 8); 154 | CellSizeProperty += Delta * smoothing; 155 | if (CellSizeProperty > 256) 156 | CellSizeProperty = 256; 157 | else if (CellSizeProperty < 4) 158 | CellSizeProperty = 4; 159 | PanningX = (OldX * CellSizeProperty) - X + ModX; 160 | PanningY = (OldY * CellSizeProperty) - Y + ModY; 161 | Base.Draw(); 162 | } 163 | 164 | void SetPanningParameters() 165 | { 166 | var CanvasDimensions = Base.GetDimension(); 167 | var CanvasWidth = CanvasDimensions.Width; 168 | var CanvasHeight = CanvasDimensions.Height; 169 | this.PanningWidth = CanvasWidth / CellSizeProperty; 170 | this.PanningHeight = CanvasHeight / CellSizeProperty; 171 | this.PanningLeft = PanningX / CellSizeProperty; 172 | this.PanningTop = PanningY / CellSizeProperty; 173 | this.PanningRight = PanningLeft + PanningWidth + 1; 174 | this.PanningBottom = PanningTop + PanningHeight + 1; 175 | } 176 | 177 | public void SetPanningXY(int X, int Y) 178 | { 179 | PanningX = (int) ((X - (PanningWidth / 2.0)) * CellSize); 180 | PanningY = (int) ((Y - (PanningHeight / 2.0)) * CellSize); 181 | } 182 | 183 | public void KeepXYOnScreen(int X, int Y) 184 | { 185 | 186 | int buffer = 5; 187 | if (X < PanningLeft || X > PanningRight || Y < PanningTop || Y > PanningBottom || 188 | buffer > PanningWidth || buffer > PanningHeight) 189 | { 190 | PanningX = (int) ((X - (PanningWidth / 2.0)) * CellSize); 191 | PanningY = (int) ((Y - (PanningHeight / 2.0)) * CellSize); 192 | } 193 | else 194 | { 195 | if (X < PanningLeft + buffer) 196 | { 197 | PanningX = (PanningLeft - 1) * CellSize; 198 | } 199 | else if (X + 1 > PanningRight - buffer) 200 | { 201 | PanningX = (PanningLeft + 1) * CellSize; 202 | } 203 | 204 | if(Y < PanningTop + buffer) 205 | { 206 | PanningY = (PanningTop - 1) * CellSize; 207 | } 208 | else if (Y + 1 > PanningBottom - buffer) 209 | { 210 | PanningY = (PanningTop + 1) * CellSize; 211 | } 212 | } 213 | } 214 | 215 | public Inv.Dimension Dimension { get; set; } 216 | public int CellSize { get => CellSizeProperty; set => CellSizeProperty = value; } 217 | public Inv.Dimension BaseDimension => Base.GetDimension(); 218 | public event Action DrawEvent; 219 | public void Draw() => Base.Draw(); 220 | private bool InitialDraw; 221 | private int CellSizeProperty; 222 | private int PanningX; 223 | private int PanningY; 224 | private Inv.Point? PanningPoint; 225 | private int PanningWidth; 226 | private int PanningHeight; 227 | private int PanningLeft; 228 | private int PanningTop; 229 | private int PanningRight; 230 | private int PanningBottom; 231 | private Patch Patch; 232 | } 233 | } -------------------------------------------------------------------------------- /Portable/ColorPallete.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text.RegularExpressions; 4 | using Inv; 5 | 6 | namespace Portable 7 | { 8 | // See http://paletton.com 9 | public static class ColorPallette 10 | { 11 | 12 | public static Colour PrimaryColor; 13 | public static Colour PrimaryColorLightest; 14 | public static Colour PrimaryColorLighter; 15 | public static Colour PrimaryColorDarker; 16 | public static Colour PrimaryColorDarkest; 17 | 18 | public static Colour Secondary1Color; 19 | public static Colour Secondary1ColorLightest; 20 | public static Colour Secondary1ColorLighter; 21 | public static Colour Secondary1ColorDarker; 22 | public static Colour Secondary1ColorDarkest; 23 | 24 | public static Colour Secondary2Color; 25 | public static Colour Secondary2ColorLightest; 26 | public static Colour Secondary2ColorLighter; 27 | public static Colour Secondary2ColorDarker; 28 | public static Colour Secondary2ColorDarkest; 29 | 30 | public static Colour ComplementColor; 31 | public static Colour ComplementColorLightest; 32 | public static Colour ComplementColorLighter; 33 | public static Colour ComplementColorDarker; 34 | public static Colour ComplementColorDarkest; 35 | 36 | 37 | static ColorPallette() 38 | { 39 | var lines = colorMapString.Split('\n'); 40 | List colors = new List(); 41 | foreach(var line in lines) 42 | { 43 | Match colorMatch = rgbRe.Match(line); 44 | if(colorMatch.Success) 45 | { 46 | var r = byte.Parse(colorMatch.Groups["r"].Value); 47 | var g = byte.Parse(colorMatch.Groups["g"].Value); 48 | var b = byte.Parse(colorMatch.Groups["b"].Value); 49 | var color = Colour.FromArgb(byte.MaxValue, r, g, b); 50 | colors.Add(color); 51 | } 52 | } 53 | PrimaryColor = colors[0]; 54 | PrimaryColorLightest = colors[1]; 55 | PrimaryColorLighter = colors[2]; 56 | PrimaryColorDarker = colors[3]; 57 | PrimaryColorDarkest = colors[4]; 58 | 59 | Secondary1Color = colors[5]; 60 | Secondary1ColorLightest = colors[6]; 61 | Secondary1ColorLighter = colors[7]; 62 | Secondary1ColorDarker = colors[8]; 63 | Secondary1ColorDarkest = colors[9]; 64 | 65 | Secondary2Color = colors[10]; 66 | Secondary2ColorLightest = colors[11]; 67 | Secondary2ColorLighter = colors[12]; 68 | Secondary2ColorDarker = colors[13]; 69 | Secondary2ColorDarkest = colors[14]; 70 | 71 | ComplementColor = colors[15]; 72 | ComplementColorLightest = colors[16]; 73 | ComplementColorLighter = colors[17]; 74 | ComplementColorDarker = colors[18]; 75 | ComplementColorDarkest = colors[19]; 76 | } 77 | 78 | static Regex rgbRe = new Regex(@" rgb\((?[ \d]+),(?[ \d]+),(?[ \d]+)\)"); 79 | 80 | 81 | 82 | 83 | 84 | // I'm too lazy to keep copy-pasting colors. Just read in the whole text map from paletton. 85 | static string colorMapString = @" 86 | ##### Color Palette by Paletton.com 87 | ##### Palette URL: http://paletton.com/#uid=72O0u0klVl63+Jtc+t1uFdmQU5s 88 | 89 | 90 | *** Primary color: 91 | 92 | shade 0 = #30882B = rgb( 48,136, 43) = rgba( 48,136, 43,1) = rgb0(0.188,0.533,0.169) 93 | shade 1 = #C9E4C8 = rgb(201,228,200) = rgba(201,228,200,1) = rgb0(0.788,0.894,0.784) 94 | shade 2 = #73BB6F = rgb(115,187,111) = rgba(115,187,111,1) = rgb0(0.451,0.733,0.435) 95 | shade 3 = #085604 = rgb( 8, 86, 4) = rgba( 8, 86, 4,1) = rgb0(0.031,0.337,0.016) 96 | shade 4 = #022300 = rgb( 2, 35, 0) = rgba( 2, 35, 0,1) = rgb0(0.008,0.137,0) 97 | 98 | *** Secondary color (1): 99 | 100 | shade 0 = #206664 = rgb( 32,102,100) = rgba( 32,102,100,1) = rgb0(0.125,0.4,0.392) 101 | shade 1 = #AFC8C7 = rgb(175,200,199) = rgba(175,200,199,1) = rgb0(0.686,0.784,0.78) 102 | shade 2 = #538D8A = rgb( 83,141,138) = rgba( 83,141,138,1) = rgb0(0.325,0.553,0.541) 103 | shade 3 = #03413E = rgb( 3, 65, 62) = rgba( 3, 65, 62,1) = rgb0(0.012,0.255,0.243) 104 | shade 4 = #001A19 = rgb( 0, 26, 25) = rgba( 0, 26, 25,1) = rgb0(0,0.102,0.098) 105 | 106 | *** Secondary color (2): 107 | 108 | shade 0 = #A86835 = rgb(168,104, 53) = rgba(168,104, 53,1) = rgb0(0.659,0.408,0.208) 109 | shade 1 = #FFEDDF = rgb(255,237,223) = rgba(255,237,223,1) = rgb0(1,0.929,0.875) 110 | shade 2 = #E7B389 = rgb(231,179,137) = rgba(231,179,137,1) = rgb0(0.906,0.702,0.537) 111 | shade 3 = #6A3204 = rgb(106, 50, 4) = rgba(106, 50, 4,1) = rgb0(0.416,0.196,0.016) 112 | shade 4 = #2B1300 = rgb( 43, 19, 0) = rgba( 43, 19, 0,1) = rgb0(0.169,0.075,0) 113 | 114 | *** Complement color: 115 | 116 | shade 0 = #A73537 = rgb(167, 53, 55) = rgba(167, 53, 55,1) = rgb0(0.655,0.208,0.216) 117 | shade 1 = #FEDEDF = rgb(254,222,223) = rgba(254,222,223,1) = rgb0(0.996,0.871,0.875) 118 | shade 2 = #E5888B = rgb(229,136,139) = rgba(229,136,139,1) = rgb0(0.898,0.533,0.545) 119 | shade 3 = #690407 = rgb(105, 4, 7) = rgba(105, 4, 7,1) = rgb0(0.412,0.016,0.027) 120 | shade 4 = #2B0001 = rgb( 43, 0, 1) = rgba( 43, 0, 1,1) = rgb0(0.169,0,0.004) 121 | 122 | 123 | ##### Generated by Paletton.com (c) 2002-2014 124 | "; 125 | } 126 | } -------------------------------------------------------------------------------- /Portable/EntityData.cs: -------------------------------------------------------------------------------- 1 | using EntityComponentSystemCSharp.Components; 2 | using EntityComponentSystemCSharp; 3 | using static EntityComponentSystemCSharp.EntityManager; 4 | using Inv; 5 | 6 | namespace Portable 7 | { 8 | /// 9 | /// Provides a table of standard display data for entities. 10 | /// 11 | internal class EntityData 12 | { 13 | Label _name; 14 | Label _health; 15 | Label _maxHealth; 16 | Label _attack; 17 | Label _accuracy; 18 | Label _defense; 19 | Label _gold; 20 | Label _speed; 21 | Table _table; 22 | 23 | 24 | public Table Table => _table; 25 | 26 | public EntityData(Surface surface, Colour fontColor, Colour backgroundColor) 27 | { 28 | _table = surface.NewTable(); 29 | _table.Background.Colour = backgroundColor; 30 | _name = surface.NewLabel(); 31 | var n = surface.NewLabel(); 32 | n.Text = "Name: "; 33 | 34 | _health = surface.NewLabel(); 35 | _maxHealth = surface.NewLabel(); 36 | var h = surface.NewLabel(); 37 | h.Text = "Health: "; 38 | var divider = surface.NewLabel(); 39 | divider.Text = " / "; 40 | var healthPanel = surface.NewHorizontalStack(); 41 | healthPanel.AddPanel(h); 42 | healthPanel.AddPanel(_health); 43 | var maxHealthPanel = surface.NewHorizontalStack(); 44 | maxHealthPanel.AddPanel(divider); 45 | maxHealthPanel.AddPanel(_maxHealth); 46 | 47 | _attack = surface.NewLabel(); 48 | var at = surface.NewLabel(); 49 | at.Text = "Attack: "; 50 | 51 | _accuracy = surface.NewLabel(); 52 | var ac = surface.NewLabel(); 53 | ac.Text = "Accuracy: "; 54 | 55 | _defense = surface.NewLabel(); 56 | var def = surface.NewLabel(); 57 | def.Text = "Defense: "; 58 | 59 | _speed = surface.NewLabel(); 60 | var s = surface.NewLabel(); 61 | s.Text = "Speed: "; 62 | 63 | _gold = surface.NewLabel(); 64 | var gl = surface.NewLabel(); 65 | gl.Text = "Gold: "; 66 | 67 | _table = surface.NewTable(); 68 | _table.Compose( 69 | new Panel[,] 70 | { 71 | {n, _name}, 72 | {healthPanel, maxHealthPanel}, 73 | {at, _attack}, 74 | {ac, _accuracy}, 75 | {def, _defense}, 76 | {s, _speed}, 77 | {gl, _gold} 78 | }); 79 | 80 | SetFontInfo(fontColor, backgroundColor); 81 | _gold.Font.Colour = Colour.Gold; 82 | var padding = _table.AddAutoRow(); 83 | padding.Star(); 84 | } 85 | 86 | private void SetFontInfo(Colour fontColor, Colour backgroundColor) 87 | { 88 | foreach(var row in _table.GetRows()) 89 | { 90 | row.Auto(); 91 | } 92 | 93 | foreach(var col in _table.GetColumns()) 94 | { 95 | col.Star(); 96 | } 97 | var index = 0; 98 | foreach (var cell in _table.GetCells()) 99 | { 100 | var label = cell.Content.Control as Label; 101 | if (label != null) 102 | { 103 | label.Font.Colour = fontColor; 104 | label.Font.Large(); 105 | label.Font.Bold(); 106 | if(index % 2 == 1) 107 | { 108 | label.Alignment.CenterRight(); 109 | } 110 | label.Background.Colour = backgroundColor; 111 | } 112 | var stack = cell.Content.Control as Stack; 113 | if (stack != null) 114 | { 115 | foreach (var panel in stack.GetPanels()) 116 | { 117 | label = panel.Control as Label; 118 | if (label != null) 119 | { 120 | label.Font.Colour = fontColor; 121 | label.Font.Large(); 122 | label.Font.Bold(); 123 | if(index % 2 == 1) 124 | { 125 | label.Alignment.CenterRight(); 126 | } 127 | label.Background.Colour = backgroundColor; 128 | } 129 | } 130 | } 131 | index++; 132 | } 133 | } 134 | 135 | public void SetData(Entity entity) 136 | { 137 | var alive = entity.GetComponent(); 138 | var name = entity.GetComponent(); 139 | var attack = entity.GetComponent(); 140 | var defense = entity.GetComponent(); 141 | var actor = entity.GetComponent(); 142 | 143 | if (alive != null) 144 | { 145 | _health.Text = alive.Health.ToString(); 146 | _maxHealth.Text = alive.MaxHealth.ToString(); 147 | } 148 | 149 | if(name != null) 150 | { 151 | _name.Text = name.NameString; 152 | } 153 | 154 | if(attack != null) 155 | { 156 | _attack.Text = attack.Power.ToString(); 157 | _accuracy.Text = attack.Accuracy.ToString(); 158 | } 159 | 160 | if(defense != null) 161 | { 162 | _defense.Text = defense.Chance.ToString(); 163 | } 164 | 165 | if(actor != null) 166 | { 167 | _gold.Text = actor.Gold.ToString(); 168 | _speed.Text = actor.Speed.ToString(); 169 | } 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /Portable/MegaDungeonUI.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Collections.Generic; 4 | using EntityComponentSystemCSharp.Components; 5 | using EntityComponentSystemCSharp; 6 | using static EntityComponentSystemCSharp.EntityManager; 7 | using static Portable.MegaDungeonUIConstants; 8 | using Inv; 9 | 10 | namespace Portable 11 | { 12 | 13 | public class MegaDungeonUI 14 | { 15 | int _horizontalCellCount; 16 | int _verticalCellCount; 17 | Surface _surface; 18 | MegaDungeon.Engine _engine; 19 | MegaDungeon.PlayerInput _lastInput = MegaDungeon.PlayerInput.NONE; 20 | TileManager _tileManager; 21 | Dictionary _lastLocation = new Dictionary(); 22 | Dictionary _actorLocationMap = new Dictionary(); 23 | Cloth _cloth; 24 | Dock _outerDock; 25 | Dock _innerDock; 26 | Label _topLabel; 27 | Label _bottomLabel; 28 | Label _rightLabel; 29 | Label _gameOver; 30 | EntityData _leftPanel; 31 | bool _showDebugInfo = false; 32 | 33 | static Dictionary UICommands = new Dictionary(); 34 | public MegaDungeon.PlayerInput LastInput { get => _lastInput; set => _lastInput = value; } 35 | 36 | /// 37 | /// Constructor for Main UI logic class. Sets up all UI windows. 38 | /// 39 | /// 40 | /// 41 | /// 42 | public MegaDungeonUI(Surface surface, int horizontalCellCount, int verticalCellCount) 43 | { 44 | _horizontalCellCount = horizontalCellCount; 45 | _verticalCellCount = verticalCellCount; 46 | 47 | var directory = surface.Window.Application.Directory; 48 | _tileManager = new TileManager(directory.NewAsset("absurd64.bmp"), directory.NewAsset("tiledata.json")); 49 | _engine = new MegaDungeon.Engine(horizontalCellCount, verticalCellCount, _tileManager); 50 | 51 | _tileManager = new TileManager(directory.NewAsset("absurd64.bmp"), directory.NewAsset("tiledata.json")); 52 | _engine = new MegaDungeon.Engine(horizontalCellCount, verticalCellCount, _tileManager); 53 | _surface = surface; 54 | _cloth = CreateCloth(); 55 | _outerDock = _surface.NewDock(Inv.Orientation.Vertical); 56 | _innerDock = _surface.NewDock(Inv.Orientation.Horizontal); 57 | 58 | _topLabel = InitLabel("Top", ColorPallette.PrimaryColorLightest, ColorPallette.PrimaryColorDarkest, ColorPallette.PrimaryColorDarker); 59 | _bottomLabel = InitLabel("Bottom", ColorPallette.Secondary1ColorLightest, ColorPallette.Secondary1ColorDarkest, ColorPallette.Secondary1ColorDarker); 60 | _outerDock.AddHeader(_topLabel); 61 | _outerDock.AddClient(_innerDock); 62 | _outerDock.AddFooter(_bottomLabel); 63 | 64 | var vstack = _surface.NewVerticalStack(); 65 | vstack.Background.Colour = ColorPallette.Secondary1ColorDarkest; 66 | vstack.Border.Set(5); 67 | vstack.Border.Colour = ColorPallette.Secondary1ColorDarkest; 68 | 69 | _leftPanel = new EntityData(_surface, ColorPallette.Secondary1ColorLightest, ColorPallette.Secondary1ColorDarkest); 70 | vstack.AddPanel(_leftPanel.Table); 71 | _rightLabel = InitLabel("Right", ColorPallette.ComplementColorLightest, ColorPallette.ComplementColorDarkest, ColorPallette.ComplementColorDarker); 72 | _innerDock.AddHeader(vstack); 73 | _innerDock.AddClient(_cloth); 74 | _innerDock.AddFooter(_rightLabel); 75 | _surface.Content = _outerDock; 76 | _surface.ComposeEvent += Warmup(); 77 | 78 | _gameOver = _surface.NewLabel(); 79 | _gameOver.Text = "YOU HAVE DIED."; 80 | _gameOver.Font.ExtraMassive(); 81 | _gameOver.Font.Colour = Colour.Red; 82 | _gameOver.Background.Colour = Colour.DarkBlue; 83 | _gameOver.Justify.Center(); 84 | 85 | InitUiCommands(); 86 | 87 | _engine = new MegaDungeon.Engine(horizontalCellCount, verticalCellCount, _tileManager); 88 | } 89 | 90 | /// 91 | /// Commands the only do something in the UI layer and are not passed into the game engine. 92 | /// 93 | void InitUiCommands() 94 | { 95 | UICommands[Inv.Key.Plus] = () => {_cloth.Zoom(0,0,1);}; 96 | UICommands[Inv.Key.Minus] = () => {_cloth.Zoom(0,0,-1);}; 97 | UICommands[Inv.Key.F2] = () => {_showDebugInfo = !_showDebugInfo;_cloth.Draw();}; 98 | } 99 | /// 100 | /// Check for full _cloth init before going to usual update 101 | /// 102 | /// null 103 | /// 104 | /// Update gets called a few times before the window is fully laid out. 105 | /// When base dimensions are available center the player and connect main Update(); 106 | /// (Cannot use a lambda because -= won't be able to unregister without a method handle.) 107 | /// 108 | System.Action Warmup() 109 | { 110 | return new Action( () => 111 | { 112 | if(_cloth.BaseDimension.Height == 0) 113 | { 114 | return; 115 | } 116 | _surface.ComposeEvent -= Warmup(); 117 | _cloth.SetPanningXY(_engine.PlayerLocation.X, _engine.PlayerLocation.Y); 118 | GetActorsFromEngine(); 119 | _leftPanel.SetData(_engine.PlayerEntity); 120 | _surface.ComposeEvent += () => Update(); 121 | _cloth.Draw(); 122 | }); 123 | } 124 | 125 | /// 126 | /// Update one atomic unit of the UI. 127 | /// 128 | /// 129 | /// This method is the pump for the game. It should be fast enough to always return in less than 130 | /// one frame (1/60th sec.) 131 | /// 132 | void Update() 133 | { 134 | if (_lastInput != MegaDungeon.PlayerInput.NONE) 135 | { 136 | if(!_engine.PlayerEntity.HasComponent()) 137 | { 138 | _surface.Content = _gameOver; 139 | return; 140 | } 141 | _engine.DoTurn(_lastInput); 142 | GetActorsFromEngine(); 143 | _cloth.KeepXYOnScreen(_engine.PlayerLocation.X, _engine.PlayerLocation.Y); 144 | _bottomLabel.Text = string.Join("\n", _engine.Messages); 145 | _leftPanel.SetData(_engine.PlayerEntity); 146 | _cloth.Draw(); 147 | _lastInput = MegaDungeon.PlayerInput.NONE; 148 | } 149 | } 150 | 151 | public void AcceptInput(Inv.Keystroke keystroke) 152 | { 153 | if (KeyMap.ContainsKey(keystroke.Key)) 154 | { 155 | _lastInput = KeyMap[keystroke.Key]; 156 | } 157 | else if (UICommands.ContainsKey(keystroke.Key)) 158 | { 159 | UICommands[keystroke.Key](); 160 | } 161 | } 162 | 163 | Label InitLabel(string text, Colour fontColor, Colour border, Colour background) 164 | { 165 | var newLabel = _surface.NewLabel(); 166 | newLabel.Text = text; 167 | newLabel.Background.Colour = background; 168 | newLabel.Font.Colour = fontColor; 169 | newLabel.Border.Colour = border; 170 | newLabel.Border.Set(1); 171 | return newLabel; 172 | } 173 | 174 | internal Cloth CreateCloth() 175 | { 176 | var cloth = new Cloth(); 177 | cloth.Dimension = new Inv.Dimension(_horizontalCellCount, _verticalCellCount); 178 | cloth.CellSize = (_surface.Window.Width / _horizontalCellCount) * 2; //How much of initial map to show. 179 | cloth.Draw(); 180 | cloth.DrawEvent += (DC, patch) => Cloth_DrawEvent(DC, patch); 181 | return cloth; 182 | } 183 | 184 | void Cloth_DrawEvent(DrawContract dc, Patch patch) 185 | { 186 | var point = new RogueSharp.Point(patch.X, patch.Y); 187 | int glyph; 188 | if(_showDebugInfo) 189 | { 190 | glyph = _engine.RevealedFloor[patch.X, patch.Y]; 191 | } 192 | else 193 | { 194 | glyph = _engine.Floor[patch.X, patch.Y]; 195 | } 196 | 197 | Inv.Image image; 198 | if(_engine.Viewable.Contains(point) || _showDebugInfo) 199 | { 200 | if(_actorLocationMap.ContainsKey(patch.X + (patch.Y * _horizontalCellCount))) 201 | { 202 | glyph = _actorLocationMap[patch.X + (patch.Y * _horizontalCellCount)]; 203 | image = _tileManager.GetInvImage(glyph); 204 | dc.DrawImage(image, patch.Rect); 205 | if(_showDebugInfo) 206 | { 207 | foreach(var loc in _lastLocation) 208 | { 209 | if(loc.Value.X == patch.X && loc.Value.Y == patch.Y) 210 | { 211 | DrawText(loc.Key.Id.ToString(), dc, patch); 212 | } 213 | } 214 | } 215 | } 216 | else 217 | { 218 | image = _tileManager.GetInvImage(glyph); 219 | dc.DrawImage(image, patch.Rect); 220 | } 221 | } 222 | else 223 | { 224 | image = _tileManager.GetInvImageDark(glyph); 225 | dc.DrawImage(image, patch.Rect); 226 | } 227 | } 228 | 229 | void DrawText(string text, DrawContract dc, Patch patch) 230 | { 231 | dc.DrawText(text, "Courier", 11,FontWeight.Regular, Colour.YellowGreen, new Point(patch.Rect.Left, patch.Rect.Top), HorizontalPosition.Left, VerticalPosition.Top); 232 | } 233 | void GetActorsFromEngine() 234 | { 235 | // Remove old location from the map. 236 | foreach (var actor in _engine.GetEntityManager().GetAllEntitiesWithComponent()) 237 | { 238 | var location = actor.GetComponent(); 239 | var glyph = actor.GetComponent(); 240 | if (_lastLocation.ContainsKey(actor)) 241 | { 242 | var last = _lastLocation[actor]; 243 | _actorLocationMap.Remove(last.X + (last.Y * _horizontalCellCount)); 244 | } 245 | } 246 | 247 | // Add new locations 248 | foreach(var actor in _engine.GetEntityManager().GetAllEntitiesWithComponent()) 249 | { 250 | var location = actor.GetComponent(); 251 | var glyph = actor.GetComponent(); 252 | _actorLocationMap[location.X + (location.Y * _horizontalCellCount)] = glyph.glyph; 253 | _lastLocation[actor] = new EntityComponentSystemCSharp.Components.Location() {X = location.X, Y = location.Y}; 254 | } 255 | } 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /Portable/MegaDungeonUIConstants.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Inv; 3 | 4 | namespace Portable 5 | { 6 | public static class MegaDungeonUIConstants 7 | { 8 | /// 9 | /// Mapping from UI implementation to game. 10 | /// 11 | /// 12 | /// Enforce a strong firewall between the game the UI implmentation. 13 | /// 14 | /// 15 | /// 16 | /// 17 | public static Dictionary KeyMap = new Dictionary() 18 | { 19 | {Inv.Key.n1,MegaDungeon.PlayerInput.DOWNLEFT}, 20 | {Inv.Key.n2,MegaDungeon.PlayerInput.DOWN}, 21 | {Inv.Key.n3,MegaDungeon.PlayerInput.DOWNRIGHT}, 22 | {Inv.Key.n4,MegaDungeon.PlayerInput.LEFT}, 23 | {Inv.Key.n5,MegaDungeon.PlayerInput.WAIT}, 24 | {Inv.Key.n6,MegaDungeon.PlayerInput.RIGHT}, 25 | {Inv.Key.n7,MegaDungeon.PlayerInput.UPLEFT}, 26 | {Inv.Key.n8,MegaDungeon.PlayerInput.UP}, 27 | {Inv.Key.n9,MegaDungeon.PlayerInput.UPRIGHT}, 28 | {Inv.Key.Up,MegaDungeon.PlayerInput.UP}, 29 | {Inv.Key.Down,MegaDungeon.PlayerInput.DOWN}, 30 | {Inv.Key.Left,MegaDungeon.PlayerInput.LEFT}, 31 | {Inv.Key.Right,MegaDungeon.PlayerInput.RIGHT}, 32 | {Inv.Key.Space,MegaDungeon.PlayerInput.WAIT}, 33 | 34 | // vi keys 35 | {Inv.Key.B,MegaDungeon.PlayerInput.DOWNLEFT}, 36 | {Inv.Key.J,MegaDungeon.PlayerInput.DOWN}, 37 | {Inv.Key.N,MegaDungeon.PlayerInput.DOWNRIGHT}, 38 | {Inv.Key.H,MegaDungeon.PlayerInput.LEFT}, 39 | {Inv.Key.L,MegaDungeon.PlayerInput.RIGHT}, 40 | {Inv.Key.Y,MegaDungeon.PlayerInput.UPLEFT}, 41 | {Inv.Key.K,MegaDungeon.PlayerInput.UP}, 42 | {Inv.Key.U,MegaDungeon.PlayerInput.UPRIGHT}, 43 | 44 | // qWeASDzc 45 | {Inv.Key.Z,MegaDungeon.PlayerInput.DOWNLEFT}, 46 | {Inv.Key.S,MegaDungeon.PlayerInput.DOWN}, 47 | {Inv.Key.C,MegaDungeon.PlayerInput.DOWNRIGHT}, 48 | {Inv.Key.A,MegaDungeon.PlayerInput.LEFT}, 49 | {Inv.Key.D,MegaDungeon.PlayerInput.RIGHT}, 50 | {Inv.Key.Q,MegaDungeon.PlayerInput.UPLEFT}, 51 | {Inv.Key.W,MegaDungeon.PlayerInput.UP}, 52 | {Inv.Key.E,MegaDungeon.PlayerInput.UPRIGHT}, 53 | }; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Portable/Portable.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard20 4 | $(SolutionDir)\bin\$(Configuration)\$(AssemblyName)\ 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Portable/Shell.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Inv; 6 | 7 | namespace Portable 8 | { 9 | public static class Shell 10 | { 11 | static TimeSpan frameTime = TimeSpan.FromMilliseconds(8); 12 | public static void Install(Inv.Application application) 13 | { 14 | application.Title = "MegaDungeon"; 15 | var surface = application.Window.NewSurface(); 16 | var h = application.Window.Height; 17 | var w = application.Window.Width; 18 | var start = DateTime.UtcNow; 19 | var ui = new MegaDungeonUI(surface, 60, 40); 20 | var end = DateTime.UtcNow; 21 | var ms = (end - start).TotalMilliseconds; 22 | Console.WriteLine($"Initialized in {ms} milliseconds"); 23 | 24 | surface.ArrangeEvent += () => 25 | { 26 | Surface_ArrangeEvent(surface); 27 | }; 28 | 29 | application.Window.Transition(surface); 30 | 31 | surface.ComposeEvent += () => 32 | { 33 | Surface_ComposeEvent(ui); 34 | }; 35 | 36 | surface.KeystrokeEvent += (keyStroke) => 37 | { 38 | Surface_KeystrokeEvent(keyStroke, ui); 39 | }; 40 | Console.WriteLine("Boot completed."); 41 | } 42 | 43 | static void Surface_KeystrokeEvent(Keystroke keystroke, MegaDungeonUI ui) 44 | { 45 | // Console.WriteLine($"{keystroke.Modifier}{keystroke.Key}"); 46 | ui.AcceptInput(keystroke); 47 | } 48 | static void Surface_ArrangeEvent(Surface surface) 49 | { 50 | 51 | } 52 | 53 | // Fires up to 60 times a second. 54 | static void Surface_ComposeEvent(MegaDungeonUI ui) 55 | { 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Portable/TileManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SixLabors.ImageSharp; 4 | using SixLabors.ImageSharp.Processing; 5 | using SixLabors.Primitives; 6 | using Newtonsoft.Json; 7 | using System.Collections.Generic; 8 | using MegaDungeon.Contracts; 9 | using SixLabors.ImageSharp.PixelFormats; 10 | 11 | namespace Portable 12 | { 13 | public class TileManager : ITileManager 14 | { 15 | Image _tileset; 16 | int _tileSize; 17 | TileData _tileData; 18 | 19 | public Inv.Image TransparentDarken; 20 | 21 | Dictionary _tileCache = new Dictionary(); 22 | Dictionary _darkTileCache = new Dictionary(); 23 | Dictionary _glyphsByName = new Dictionary(); 24 | 25 | public TileManager(Inv.Asset tileImageFile, Inv.Asset tileDataJson) 26 | { 27 | using (var tileStream = tileImageFile.Open()) 28 | { 29 | _tileset = Image.Load(tileStream); 30 | } 31 | 32 | _tileData = JsonConvert.DeserializeObject(tileDataJson.AsText().ReadAll()); 33 | _tileSize = _tileData.tile_size; 34 | 35 | foreach(var tile in _tileData.data) 36 | { 37 | _glyphsByName.Add(tile.Value.name, int.Parse(tile.Key)); 38 | } 39 | 40 | } 41 | 42 | public int GetGlyphNumByName(string name) 43 | { 44 | return _glyphsByName[name]; 45 | } 46 | 47 | public Inv.Image GetInvImage(int index) 48 | { 49 | if(!_tileCache.ContainsKey(index)) 50 | { 51 | var invImage = new Inv.Image(GetTileBmpBytes(index), "bmp"); 52 | _tileCache.Add(index, invImage); 53 | } 54 | return _tileCache[index]; 55 | } 56 | 57 | public Inv.Image GetInvImageDark(int index) 58 | { 59 | Inv.Image invImage; 60 | if(_darkTileCache.ContainsKey(index)) 61 | { 62 | invImage = _darkTileCache[index]; 63 | } 64 | else 65 | { 66 | var tile = GetTileAsSLImage(index); 67 | tile.Mutate(m => m.Brightness(0.5F)); 68 | invImage = new Inv.Image(GetBytesFromImage(tile), "bmp"); 69 | _darkTileCache[index] = invImage; 70 | } 71 | return invImage; 72 | } 73 | 74 | public byte[] GetTileBmpBytes(int index) 75 | { 76 | Image tile = GetTileAsSLImage(index); 77 | return GetBytesFromImage(tile); 78 | } 79 | 80 | public Image GetTileAsSLImage(int index) 81 | { 82 | var x = (index * _tileSize) % _tileset.Width; 83 | var y = _tileSize * (int)((index * _tileSize) / _tileset.Width); 84 | var tile = _tileset.Clone(m => m.Crop(new Rectangle(x, y, _tileSize, _tileSize))); 85 | return tile; 86 | } 87 | 88 | private static byte[] GetBytesFromImage(Image tile) 89 | { 90 | byte[] imgBytes; 91 | using (var memstream = new MemoryStream()) 92 | { 93 | var enc = new SixLabors.ImageSharp.Formats.Bmp.BmpEncoder(); 94 | enc.BitsPerPixel = SixLabors.ImageSharp.Formats.Bmp.BmpBitsPerPixel.Pixel32; 95 | tile.Save(memstream, enc); 96 | imgBytes = new Byte[memstream.Length]; 97 | memstream.Seek(0, SeekOrigin.Begin); 98 | memstream.Read(imgBytes, 0, imgBytes.Length); 99 | } 100 | return imgBytes; 101 | } 102 | 103 | Image DrawImageOnImageExample(Image tile) 104 | { 105 | var borderSize = 8; 106 | var borderRect = new Rectangle(borderSize, 0, tile.Width - (borderSize * 2), borderSize); 107 | var borderImage = tile.Clone(c => c.Crop(borderRect)); 108 | var point = new Point(borderSize, 0); 109 | var newTile = new Image(tile.Width, tile.Height); 110 | newTile.Mutate( i => i.DrawImage(borderImage,point, 1.0F)); 111 | 112 | return newTile; 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # InventionHack 2 | The C# Roguelike built on top of the [Invention API](https://gitlab.com/hodgskin-callan/Invention) by Callan Hodgskin and [RogueSharp](https://github.com/FaronBracy/RogueSharp) by FaronBracy. 3 | ## The Mission 4 | Use the Invention API to create a basic roguelike with all the features of the [Roguesharp C# tutorial](https://roguesharp.wordpress.com/) and put it on github with an MIT license as a jumping off point for aspiring roguelike creators. Primarily those on [r/roguelikedev](https://www.reddit.com/r/roguelikedev/). 5 | 6 | ![](InventionHackGameplay.gif) 7 | 8 | ## Features 9 | 10 | - Basic roguelike gameplay 11 | - Line of site 12 | - Random floor creation 13 | - Basic combat 14 | - Speed system 15 | - RDBMS style ECS system 16 | - UI is loosely coupled to the underlying game engine 17 | - Builds with the dotnet.exe command 18 | - Not too buggy! 19 | - Invention is a very good UI engine and the starter game only scratches the surface of whats possible with it. 20 | 21 | ## Cloning, Building and running in Windows 10 22 | There may be other valid ways to build this. 23 | #### Pre-Reqs 24 | 25 | - Visual Studio 2017/2019 community edition 26 | - Git 27 | - [Dotnet 4.6 developer pack](https://www.microsoft.com/en-us/download/details.aspx?id=53321) 28 | - Optional: [Visual Studio Code](https://code.visualstudio.com/) 29 | 30 | #### Clone 31 | 32 | Change to a directory where you like to clone stuff. 33 | 34 | C:\local> git clone https://github.com/dustinandrews/InventionHackSharp.git 35 | C:\local> cd InventionHackSharp 36 | 37 | 38 | #### Build and test 39 | If you are building from the command line in Windows these commands should work. If you wish to build for Android, swap in the MegaDungeon.sln.Android file for the MegaDungeon.sln and build from Visual Studio. You will need Xamarin correctly installed. You can also build for iOS. 40 | 41 | C:\local\InventionHackSharp>dotnet build 42 | ... 43 | C:\local\InventionHackSharp\bin\Debug\EntityComponentSystemCSharp\net4.6.1\EntityComponentSystemCSharp.dll 44 | Engine -> C:\local\InventionHackSharp\bin\Debug\Engine\net461\Engine.dll 45 | Portable -> C:\local\InventionHackSharp\bin\Debug\Portable\net461\Portable.dll 46 | InventionUiWpf -> C:\local\InventionHackSharp\bin\Debug\InventionUiWpf\net461\InventionUiWpf.exe 47 | 48 | Build succeeded. 49 | 0 Warning(s) 50 | 0 Error(s) 51 | 52 | PS C:\local\InventionHackSharp> .\runtests.ps1 53 | NUnit Console Runner 3.10.0 (.NET 2.0) 54 | Copyright (c) 2019 Charlie Poole, Rob Prouse 55 | Sunday, November 17, 2019 6:47:32 PM 56 | 57 | Runtime Environment 58 | OS Version: Microsoft Windows NT 10.0.17763.0 59 | CLR Version: 4.0.30319.42000 60 | 61 | Test Files 62 | bin\Debug\Engine\net461\Engine.dll 63 | bin\Debug\EntityComponentSystemCSharp\net461\EntityComponentSystemCSharp.dll 64 | bin\Debug\FeatureDetector\net461\FeatureDetector.dll 65 | 66 | 67 | 68 | Test Run Summary 69 | Overall result: Passed 70 | Test Count: 34, Passed: 34, Failed: 0, Warnings: 0, Inconclusive: 0, Skipped: 0 71 | Start time: 2019-11-18 02:47:32Z 72 | End time: 2019-11-18 02:47:35Z 73 | Duration: 2.463 seconds 74 | 75 | 76 | #### Run the game 77 | C:\local\InventionHackSharp\bin\Debug\InventionUiWpf\net461\InventionUiWpf.exe 78 | 79 | ## Tour 80 | If you think this is cool and want to fork the repo to create your own roguelike please help yourself! Here is a brief description of the projects inside. 81 | #### Engine 82 | This is the game logic. It manages the game turns, maps and sits on top of the ECS. It also manages player specific stuff. 83 | #### EntityComponentSystemCSharp 84 | This is the Entity Component System that drives the game. Components are bare-bones C# classes with zero or more data members. The game engine calls every system for every entity each turn and gives it an opportunity to act. Systems filter for appropriate entities and change the data as appropriate. 85 | 86 | ### FeatureDetector 87 | Reads dungeon maps and flags walls and candidate locations for doors. It relies on [NumSharp](https://github.com/SciSharp/NumSharp) and uses a convolution filter. NumSharp is the C# port of numpy from Python. Things that are a breeze and super fast with numpy can be a downright chore in C#. NumSharp is still in beta and it shows. I plan to extend the convolution filter for use in cellular automata level generation at some point. 88 | 89 | ### InventionUiWpf 90 | This is the Windows WPF project that makes the UI work on that platform. Right now it's the only supported platform, but the other ones shouldn't be too hard to get working. I want to keep compatibility with dotnet.exe and vscode, so I haven't tried to integrate them. 91 | 92 | ### lib 93 | This is a custom build of the Invention API for x64 since the current nuget packages were x86 and vscode can only debug x64 binaries. 94 | ### Portable (AKA the Portable UI) 95 | This is the platform agnostic UI code that displays the game and ties the user to the engine. 96 | 97 | ## Pull requests 98 | I am happy to receive any pull requests and consider them. As the point of this repository is to be a clean starting point, new features are (probably) not going to be added. Any pull requests should: 99 | 100 | - Fix a bug 101 | - Make the code cleaner and easier to understand 102 | - Add unit tests that will either help downstream authors, be explanatory code, or both 103 | - Anything else that makes this a better starting point without making it too complex. 104 | 105 | ## Various Provisos, Quid pro quo and Caveats 106 | - Projects build .net 4.6.1 binaries. 107 | - There is no sound support in the custom Invention binaries as they require a third party library that requires licensing. 108 | - "dotnet.exe build" and "dotnet.exe test" must continue to work for pull requests to be accepted. 109 | 110 | ## Getting Help 111 | The primary help channel is [r/roguelikedev](https://www.reddit.com/r/roguelikedev/). Use the [announcement thread](https://www.reddit.com/r/roguelikedev/comments/ds3n8y/inventionhacksharp_the_basic_windows_c_roguelike/) or tag u/madsciencestache. For Invention help the Invention channel on the [Pathos](https://pathos.azurewebsites.net/) Lounge discord is a good place or tag u/callanh on Reddit. 112 | 113 | ## TODO: 114 | 115 | - Consider changing the MegaDungeon namespaces. (MegaDungeon is my own fork where I will develop my unique game.) 116 | - ~~Remove NumSharp since it's incomplete and much slower for this use than plain C#.~~ Done! 117 | 118 | ## Change-log: 119 | 11/17/2019 - Callanh has upgraded the Invention nuget to support this project! Accepted pull request and added some multi-targeting to keep Nunit tests working since it doesn't support netstandard yet. 120 | 121 | ## Backstory 122 | After stumbling on [Pathos](https://pathos.azurewebsites.net/) the Nethack Reboot I learned that the author, Callan Hodgskin, built it on top of a code-first API capable of building for Windows, iOS, Android and Linux. I checked out the API and found it to be excellent. It re-ignited my desire to create a roguelike. I also want to promote Invention as a platform, so I created this repository as a basic starting point for roguelike developers who want to program in C#. 123 | -------------------------------------------------------------------------------- /absurd64.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/absurd64.bmp -------------------------------------------------------------------------------- /nuget.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dustinandrews/InventionHackSharp/2ebde7af75e82eabc18ca31d6214e54933651161/nuget.exe -------------------------------------------------------------------------------- /runtests.ps1: -------------------------------------------------------------------------------- 1 | # dotnet.exe test has problems with these multi-target dlls. 2 | # Enumerate test dlls here and run tests with this script 3 | 4 | $testFixtures = @('bin\Debug\Engine\net461\Engine.dll', 5 | 'bin\Debug\EntityComponentSystemCSharp\net461\EntityComponentSystemCSharp.dll', 6 | 'bin\Debug\FeatureDetector\net461\FeatureDetector.dll' 7 | ) 8 | 9 | $nunit = 'nunit.consolerunner\3.10.0\tools\nunit3-console.exe' 10 | $config = Invoke-Expression ".\nuget.exe locals all -list" 11 | foreach($line in $config) 12 | { 13 | if ($line -match 'global-packages: (?.*)') 14 | { 15 | $packagePath = $Matches.path 16 | $nunitPath = [System.IO.Path]::Combine($packagePath,$nunit) 17 | if(Test-Path $nunitPath -PathType Leaf) 18 | { 19 | $fixtures = [String]::Join(" ", $testFixtures) 20 | Invoke-Expression "$nunitPath $fixtures" 21 | } 22 | } 23 | } --------------------------------------------------------------------------------