diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b4332d02..14e0e436 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -60,7 +60,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: 9.x + dotnet-version: 10.x - name: Install dependencies run: dotnet restore - name: Build diff --git a/.github/workflows/dotnet-core.yml b/.github/workflows/dotnet-core.yml index 6ea3e561..e4aab27d 100644 --- a/.github/workflows/dotnet-core.yml +++ b/.github/workflows/dotnet-core.yml @@ -16,7 +16,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: 9.x + dotnet-version: 10.x - name: Install dependencies run: dotnet restore - name: Build diff --git a/.github/workflows/release-creator.yml b/.github/workflows/release-creator.yml index 9f29e313..4ad2e269 100644 --- a/.github/workflows/release-creator.yml +++ b/.github/workflows/release-creator.yml @@ -16,7 +16,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 9.x + dotnet-version: 10.x - name: Install dependencies run: dotnet restore - name: Build diff --git a/.github/workflows/sonarscan.yml b/.github/workflows/sonarscan.yml index b0951504..a72c3636 100644 --- a/.github/workflows/sonarscan.yml +++ b/.github/workflows/sonarscan.yml @@ -19,7 +19,7 @@ jobs: - name: Set up .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 9.x + dotnet-version: 10.x - name: Set up dotnet coverage shell: bash run: | @@ -51,8 +51,8 @@ jobs: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} shell: bash run: | - dotnet-sonarscanner begin /k:"Sofistico_MagiRogue" /o:"sofistico" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml + dotnet-sonarscanner begin /k:"Sofistico_MagiRogue" /o:"sofistico" /d:sonar.login="$SONAR_TOKEN" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml dotnet restore dotnet build --configuration Release --no-restore dotnet-coverage collect 'dotnet test' -f xml -o 'coverage.xml' - dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" + dotnet-sonarscanner end /d:sonar.login="$SONAR_TOKEN" diff --git a/.vscode/launch.json b/.vscode/launch.json index c5a5df84..bbd7d4b7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "build", - "program": "${workspaceFolder}/src/MagiRogue/bin/Debug/net9.0/MagiRogue.dll", + "program": "${workspaceFolder}/src/MagiRogue/bin/Debug/net10.0/MagiRogue.dll", "args": [], "cwd": "${workspaceFolder}/src/MagiRogue", "console": "internalConsole", @@ -20,7 +20,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "build", - "program": "${workspaceFolder}/src/MagiRogue/bin/Debug/net9.0/MagiRogue.dll", + "program": "${workspaceFolder}/src/MagiRogue/bin/Debug/net10.0/MagiRogue.dll", "args": ["test"], "cwd": "${workspaceFolder}/src/MagiRogue", "console": "internalConsole", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 6127a781..d57b9182 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,7 +7,7 @@ "type": "process", "args": [ "build", - "${workspaceFolder}/MagiRogue.sln", + "${workspaceFolder}/MagiRogue.slnx", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary;ForceNoAlign" ], @@ -19,7 +19,7 @@ "type": "process", "args": [ "publish", - "${workspaceFolder}/MagiRogue.sln", + "${workspaceFolder}/MagiRogue.slnx", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary;ForceNoAlign" ], @@ -38,4 +38,4 @@ "problemMatcher": "$msCompile" } ] -} \ No newline at end of file +} diff --git a/MagiRogue.sln b/MagiRogue.sln deleted file mode 100644 index 149037b0..00000000 --- a/MagiRogue.sln +++ /dev/null @@ -1,95 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.3.32922.545 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "src\MagiRogue", "src\MagiRogue\MagiRogue.csproj", "{07446F58-66E1-4B55-84FB-70C67E6E0BC8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "src\MagiRogue.Test", "src\MagiRogue.Test\MagiRogue.Test.csproj", "{16CADFB2-73B0-4322-B266-0527B9A12B49}" - ProjectSection(ProjectDependencies) = postProject - {07446F58-66E1-4B55-84FB-70C67E6E0BC8} = {07446F58-66E1-4B55-84FB-70C67E6E0BC8} - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "src\MagiRogue.LegendsConsoleViewer", "src\MagiRogue.LegendsConsoleViewer\MagiRogue.LegendsConsoleViewer.csproj", "{6AA2F259-2D24-4663-B56B-242700954B45}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1 - Game", "1 - Game", "{8454D3F7-7624-4B8C-BD1D-BBFF955E8251}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2 - Tools", "2 - Tools", "{6EEDFB15-2116-49D2-B091-CF68027EC580}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3 - Test", "3 - Test", "{CEC24325-48A3-475C-B109-92CA2C13C327}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "src\MagiRogue.Benchmarks", "src\MagiRogue.Benchmarks\MagiRogue.Benchmarks.csproj", "{ABB63633-6A69-4AB2-AC9B-A81B0D6D5C48}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1.2 - Engine", "1.2 - Engine", "{3CD9D6CB-0811-4B61-AE22-01682A8C1BBA}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1.3 - Render", "1.3 - Render", "{F2FC3775-ED52-48AA-A445-F047A661CDEA}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1.1 - Data", "1.1 - Data", "{D827073E-B105-43FF-B31F-562E0D027FF7}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "src\MagusEngine", "src\MagusEngine\MagusEngine.csproj", "{EAEC4804-2679-4AF4-9950-603FCD26637B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "src\Diviner", "src\Diviner\Diviner.csproj", "{97163240-F09C-4D10-AD6C-C0B5EECA8AF3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "src\Arquimedes", "src\Arquimedes\Arquimedes.csproj", "{080269A8-61A1-4BC4-BE3F-97783290A92A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "src\AccidentalNoiseLibrary", "src\AccidentalNoiseLibrary\AccidentalNoiseLibrary.csproj", "{7035D27D-B870-4D0F-8FAC-3B3C2682B5DA}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {07446F58-66E1-4B55-84FB-70C67E6E0BC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {07446F58-66E1-4B55-84FB-70C67E6E0BC8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {07446F58-66E1-4B55-84FB-70C67E6E0BC8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {07446F58-66E1-4B55-84FB-70C67E6E0BC8}.Release|Any CPU.Build.0 = Release|Any CPU - {16CADFB2-73B0-4322-B266-0527B9A12B49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {16CADFB2-73B0-4322-B266-0527B9A12B49}.Debug|Any CPU.Build.0 = Debug|Any CPU - {16CADFB2-73B0-4322-B266-0527B9A12B49}.Release|Any CPU.ActiveCfg = Release|Any CPU - {16CADFB2-73B0-4322-B266-0527B9A12B49}.Release|Any CPU.Build.0 = Release|Any CPU - {6AA2F259-2D24-4663-B56B-242700954B45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6AA2F259-2D24-4663-B56B-242700954B45}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6AA2F259-2D24-4663-B56B-242700954B45}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6AA2F259-2D24-4663-B56B-242700954B45}.Release|Any CPU.Build.0 = Release|Any CPU - {ABB63633-6A69-4AB2-AC9B-A81B0D6D5C48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ABB63633-6A69-4AB2-AC9B-A81B0D6D5C48}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ABB63633-6A69-4AB2-AC9B-A81B0D6D5C48}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ABB63633-6A69-4AB2-AC9B-A81B0D6D5C48}.Release|Any CPU.Build.0 = Release|Any CPU - {EAEC4804-2679-4AF4-9950-603FCD26637B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EAEC4804-2679-4AF4-9950-603FCD26637B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EAEC4804-2679-4AF4-9950-603FCD26637B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EAEC4804-2679-4AF4-9950-603FCD26637B}.Release|Any CPU.Build.0 = Release|Any CPU - {97163240-F09C-4D10-AD6C-C0B5EECA8AF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {97163240-F09C-4D10-AD6C-C0B5EECA8AF3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {97163240-F09C-4D10-AD6C-C0B5EECA8AF3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {97163240-F09C-4D10-AD6C-C0B5EECA8AF3}.Release|Any CPU.Build.0 = Release|Any CPU - {080269A8-61A1-4BC4-BE3F-97783290A92A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {080269A8-61A1-4BC4-BE3F-97783290A92A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {080269A8-61A1-4BC4-BE3F-97783290A92A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {080269A8-61A1-4BC4-BE3F-97783290A92A}.Release|Any CPU.Build.0 = Release|Any CPU - {7035D27D-B870-4D0F-8FAC-3B3C2682B5DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7035D27D-B870-4D0F-8FAC-3B3C2682B5DA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7035D27D-B870-4D0F-8FAC-3B3C2682B5DA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7035D27D-B870-4D0F-8FAC-3B3C2682B5DA}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {07446F58-66E1-4B55-84FB-70C67E6E0BC8} = {8454D3F7-7624-4B8C-BD1D-BBFF955E8251} - {16CADFB2-73B0-4322-B266-0527B9A12B49} = {CEC24325-48A3-475C-B109-92CA2C13C327} - {6AA2F259-2D24-4663-B56B-242700954B45} = {6EEDFB15-2116-49D2-B091-CF68027EC580} - {ABB63633-6A69-4AB2-AC9B-A81B0D6D5C48} = {6EEDFB15-2116-49D2-B091-CF68027EC580} - {3CD9D6CB-0811-4B61-AE22-01682A8C1BBA} = {8454D3F7-7624-4B8C-BD1D-BBFF955E8251} - {F2FC3775-ED52-48AA-A445-F047A661CDEA} = {8454D3F7-7624-4B8C-BD1D-BBFF955E8251} - {D827073E-B105-43FF-B31F-562E0D027FF7} = {8454D3F7-7624-4B8C-BD1D-BBFF955E8251} - {EAEC4804-2679-4AF4-9950-603FCD26637B} = {3CD9D6CB-0811-4B61-AE22-01682A8C1BBA} - {97163240-F09C-4D10-AD6C-C0B5EECA8AF3} = {F2FC3775-ED52-48AA-A445-F047A661CDEA} - {080269A8-61A1-4BC4-BE3F-97783290A92A} = {D827073E-B105-43FF-B31F-562E0D027FF7} - {7035D27D-B870-4D0F-8FAC-3B3C2682B5DA} = {D827073E-B105-43FF-B31F-562E0D027FF7} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {2FE90E55-E44A-4EF3-9614-020E1112F28A} - EndGlobalSection -EndGlobal diff --git a/MagiRogue.slnx b/MagiRogue.slnx new file mode 100644 index 00000000..4218a2b2 --- /dev/null +++ b/MagiRogue.slnx @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..343d04a0 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +build: + dotnet build + +run: + dotnet run --project ./src/MagiRogue -- test + +watch: + dotnet watch --project ./src/MagiRogue diff --git a/README.md b/README.md index 0a38fc78..40c97930 100644 --- a/README.md +++ b/README.md @@ -19,5 +19,3 @@ The game also includes a coven of wizards, with deep master-apprentice relations As you progress through the game, you can play as an apprentice, honing your magical skills and climbing the ranks to become a powerful archmage. Alternatively, you can choose to abandon magic altogether and live as a common person, or even strive to become a god. The possibilities are endless in MagiRogue, and the choices you make will have a profound impact on your journey through the game. - - diff --git a/build.cmd b/build.cmd deleted file mode 100644 index 6b11cb56..00000000 --- a/build.cmd +++ /dev/null @@ -1 +0,0 @@ -dotnet build diff --git a/run.cmd b/run.cmd deleted file mode 100644 index 0fd9a4eb..00000000 --- a/run.cmd +++ /dev/null @@ -1 +0,0 @@ -dotnet run --project ./src/MagiRogue -- test diff --git a/src/AccidentalNoiseLibrary/AccidentalNoiseLibrary.csproj b/src/AccidentalNoiseLibrary/AccidentalNoiseLibrary.csproj index 125f4c93..b7601447 100644 --- a/src/AccidentalNoiseLibrary/AccidentalNoiseLibrary.csproj +++ b/src/AccidentalNoiseLibrary/AccidentalNoiseLibrary.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 enable enable diff --git a/src/Arquimedes/Arquimedes.csproj b/src/Arquimedes/Arquimedes.csproj index 7b019bfc..63ec7a1f 100644 --- a/src/Arquimedes/Arquimedes.csproj +++ b/src/Arquimedes/Arquimedes.csproj @@ -1,14 +1,14 @@ - + - net9.0 + net10.0 enable enable - - + + diff --git a/src/Arquimedes/Data/Materials/material_body.json b/src/Arquimedes/Data/Materials/material_body.json index 7c1f83bf..6fbafb2c 100644 --- a/src/Arquimedes/Data/Materials/material_body.json +++ b/src/Arquimedes/Data/Materials/material_body.json @@ -12,12 +12,12 @@ "ColdDamageTemp": -56, "Color": "Gray", "Type": "Skin", - "ShearYield": 20000, - "ShearFracture": 20000, - "ShearStrainAtYield": 50000, - "ImpactYield": 10000, - "ImpactFracture": 10000, - "ImpactStrainsAtYield": 50000 + "ShearYield": 1000, + "ShearFracture": 2000, + "ShearStrainAtYield": 25000, + "ImpactYield": 500, + "ImpactFracture": 1000, + "ImpactStrainsAtYield": 25000 }, { "Id": "fat", @@ -53,12 +53,12 @@ "ColdDamageTemp": -56, "Color": "Red", "Type": "Meat", - "ShearYield": 10000, - "ShearFracture": 10000, - "ShearStrainAtYield": 50000, - "ImpactYield": 10000, - "ImpactFracture": 10000, - "ImpactStrainsAtYield": 50000 + "ShearYield": 800, + "ShearFracture": 1500, + "ShearStrainAtYield": 30000, + "ImpactYield": 400, + "ImpactFracture": 800, + "ImpactStrainsAtYield": 30000 }, { "Id": "bone", @@ -73,12 +73,12 @@ "Density": 0.5, "Color": "White", "Type": "Bone", - "ShearYield": 115000, - "ShearFracture": 130000, - "ShearStrainAtYield": 100, - "ImpactYield": 20000, - "ImpactFracture": 20000, - "ImpactStrainsAtYield": 100, + "ShearYield": 50000, + "ShearFracture": 80000, + "ShearStrainAtYield": 5000, + "ImpactYield": 15000, + "ImpactFracture": 25000, + "ImpactStrainsAtYield": 5000, "MaxEdge": 100 }, { @@ -95,7 +95,6 @@ "Density": 0.6, "Color": "White", "Type": "Teeth", - // same from bone "MaxEdge": 1000 }, { @@ -191,7 +190,6 @@ "Type": "None" }, { - // todo: Fix these values "Id": "hair", "Name": "hair material", "InheirtFrom": "skin", @@ -203,7 +201,6 @@ "Type": "None" }, { - // TODO: to fix this layer "Id": "cartilage", "Name": "cartilage material", "InheirtFrom": "skin", @@ -258,7 +255,6 @@ "Density": 0.5, "Color": "Gray", "Type": "Bone", - // more elastic than bone "ImpactYield": 200000, "ImpactFracture": 200000, "ImpactStrainsAtYield": 5000, diff --git a/src/Arquimedes/Data/Materials/material_metals.json b/src/Arquimedes/Data/Materials/material_metals.json index e16f5f66..902faa32 100644 --- a/src/Arquimedes/Data/Materials/material_metals.json +++ b/src/Arquimedes/Data/Materials/material_metals.json @@ -8,12 +8,12 @@ "MeltingPoint": 1538, "BoilingPoint": 2862, "ConfersTraits": [ "Durable", "MagicallyWeak" ], - "ShearYield": 15000, - "ShearFracture": 15000, - "ShearStrainAtYield": 100, - "ImpactYield": 120000, - "ImpactFracture": 120000, - "ImpactStrainsAtYield": 100, + "ShearYield": 80000, + "ShearFracture": 120000, + "ShearStrainAtYield": 1000, + "ImpactYield": 200000, + "ImpactFracture": 300000, + "ImpactStrainsAtYield": 1000, "MaxEdge": 1000 }, { diff --git a/src/Arquimedes/Enumerators/KeymapAction.cs b/src/Arquimedes/Enumerators/KeymapAction.cs new file mode 100644 index 00000000..8cd01a9d --- /dev/null +++ b/src/Arquimedes/Enumerators/KeymapAction.cs @@ -0,0 +1,36 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Arquimedes.Enumerators +{ + [JsonConverter(typeof(StringEnumConverter))] + public enum KeymapAction + { + MoveNorth, + MoveSouth, + MoveLeft, + MoveRight, + MoveNorthLeft, + MoveNorthRight, + MoveSouthLeft, + MoveSouthRight, + MoveUp, + MoveDown, + OpenInventory, + ThownItem, + EscapeMenu, + WaitTillRested, + WaitOneSecond, + WaitOneMoment, + PickUp, + DropItem, + CloseDoor, + OpenDoor, + Look, + SpellCasting, + WaitScreen, + ConfirmAction, + CancelAction, + Interact + } +} diff --git a/src/Arquimedes/Enumerators/WindowTag.cs b/src/Arquimedes/Enumerators/WindowTag.cs index e7bf6287..d52cf624 100644 --- a/src/Arquimedes/Enumerators/WindowTag.cs +++ b/src/Arquimedes/Enumerators/WindowTag.cs @@ -8,5 +8,7 @@ public enum WindowTag Status, Wait, Look, + Inv, + SpellCasting, } } diff --git a/src/Arquimedes/MagiPalette.cs b/src/Arquimedes/MagiPalette.cs index 51e8312d..c078ddf2 100644 --- a/src/Arquimedes/MagiPalette.cs +++ b/src/Arquimedes/MagiPalette.cs @@ -1,5 +1,4 @@ -using SadConsole.UI; -using SadRogue.Primitives; +using SadRogue.Primitives; namespace Arquimedes { @@ -8,7 +7,7 @@ public static class MagiPalette // Height Map Colors public static readonly Color DeepWaterColor = new(0, 0, 0.5f, 1); public static readonly Color ShallowWaterColor = new(25 / 255f, 25 / 255f, 150 / 255f, 1); - public static readonly Color RiverColor = new Color(30 / 255f, 120 / 255f, 200 / 255f, 1); + public static readonly Color RiverColor = new(30 / 255f, 120 / 255f, 200 / 255f, 1); public static readonly Color SandColor = new(240 / 255f, 240 / 255f, 64 / 255f, 1); public static readonly Color GrassColor = new(50 / 255f, 220 / 255f, 20 / 255f, 1); public static readonly Color ForestColor = new(16 / 255f, 160 / 255f, 0, 1); @@ -18,42 +17,42 @@ public static class MagiPalette public static readonly Color MagicColor = Color.Purple; // Heat Map Colors - public static readonly Color Coldest = new Color(0, 1, 1, 1); - public static readonly Color Colder = new Color(170 / 255f, 1, 1, 1); - public static readonly Color Cold = new Color(0, 229 / 255f, 133 / 255f, 1); - public static readonly Color Warm = new Color(1, 1, 100 / 255f, 1); - public static readonly Color Warmer = new Color(1, 100 / 255f, 0, 1); - public static readonly Color Warmest = new Color(241 / 255f, 12 / 255f, 0, 1); + public static readonly Color Coldest = new(0, 1, 1, 1); + public static readonly Color Colder = new(170 / 255f, 1, 1, 1); + public static readonly Color Cold = new(0, 229 / 255f, 133 / 255f, 1); + public static readonly Color Warm = new(1, 1, 100 / 255f, 1); + public static readonly Color Warmer = new(1, 100 / 255f, 0, 1); + public static readonly Color Warmest = new(241 / 255f, 12 / 255f, 0, 1); //Moisture map - public static readonly Color Dryest = new Color(255 / 255f, 139 / 255f, 17 / 255f, 1); - public static readonly Color Dryer = new Color(245 / 255f, 245 / 255f, 23 / 255f, 1); - public static readonly Color Dry = new Color(80 / 255f, 255 / 255f, 0 / 255f, 1); - public static readonly Color Wet = new Color(85 / 255f, 255 / 255f, 255 / 255f, 1); - public static readonly Color Wetter = new Color(20 / 255f, 70 / 255f, 255 / 255f, 1); - public static readonly Color Wettest = new Color(0 / 255f, 0 / 255f, 100 / 255f, 1); + public static readonly Color Dryest = new(255 / 255f, 139 / 255f, 17 / 255f, 1); + public static readonly Color Dryer = new(245 / 255f, 245 / 255f, 23 / 255f, 1); + public static readonly Color Dry = new(80 / 255f, 255 / 255f, 0 / 255f, 1); + public static readonly Color Wet = new(85 / 255f, 255 / 255f, 255 / 255f, 1); + public static readonly Color Wetter = new(20 / 255f, 70 / 255f, 255 / 255f, 1); + public static readonly Color Wettest = new(0 / 255f, 0 / 255f, 100 / 255f, 1); - public static readonly Color IceWater = new Color(210 / 255f, 255 / 255f, 252 / 255f, 1); - public static readonly Color ColdWater = new Color(119 / 255f, 156 / 255f, 213 / 255f, 1); - public static readonly Color RiverWater = new Color(65 / 255f, 110 / 255f, 179 / 255f, 1); + public static readonly Color IceWater = new(210 / 255f, 255 / 255f, 252 / 255f, 1); + public static readonly Color ColdWater = new(119 / 255f, 156 / 255f, 213 / 255f, 1); + public static readonly Color RiverWater = new(65 / 255f, 110 / 255f, 179 / 255f, 1); //biome map public static readonly Color Ice = Color.White; - public static readonly Color Desert = new Color(238 / 255f, 218 / 255f, 130 / 255f, 1); - public static readonly Color Savanna = new Color(177 / 255f, 209 / 255f, 110 / 255f, 1); - public static readonly Color TropicalRainforest = new Color(66 / 255f, 123 / 255f, 25 / 255f, 1); - public static readonly Color Tundra = new Color(96 / 255f, 131 / 255f, 112 / 255f, 1); - public static readonly Color TemperateRainforest = new Color(29 / 255f, 73 / 255f, 40 / 255f, 1); - public static readonly Color Grassland = new Color(164 / 255f, 225 / 255f, 99 / 255f, 1); - public static readonly Color SeasonalForest = new Color(73 / 255f, 100 / 255f, 35 / 255f, 1); - public static readonly Color BorealForest = new Color(95 / 255f, 115 / 255f, 62 / 255f, 1); - public static readonly Color Woodland = new Color(139 / 255f, 175 / 255f, 90 / 255f, 1); - - public static readonly Color Dirt = new Color(165, 103, 42); + public static readonly Color Desert = new(238 / 255f, 218 / 255f, 130 / 255f, 1); + public static readonly Color Savanna = new(177 / 255f, 209 / 255f, 110 / 255f, 1); + public static readonly Color TropicalRainforest = new(66 / 255f, 123 / 255f, 25 / 255f, 1); + public static readonly Color Tundra = new(96 / 255f, 131 / 255f, 112 / 255f, 1); + public static readonly Color TemperateRainforest = new(29 / 255f, 73 / 255f, 40 / 255f, 1); + public static readonly Color Grassland = new(164 / 255f, 225 / 255f, 99 / 255f, 1); + public static readonly Color SeasonalForest = new(73 / 255f, 100 / 255f, 35 / 255f, 1); + public static readonly Color BorealForest = new(95 / 255f, 115 / 255f, 62 / 255f, 1); + public static readonly Color Woodland = new(139 / 255f, 175 / 255f, 90 / 255f, 1); + + public static readonly Color Dirt = new(165, 103, 42); public static readonly Color DirtRoad = Color.Brown; - public static readonly Color Wood = new Color(186, 140, 99); - public static readonly Color DarkWood = new Color(87, 65, 46); - public static readonly Color UnclearGlass = new Color(183, 183, 189); + public static readonly Color Wood = new(186, 140, 99); + public static readonly Color DarkWood = new(87, 65, 46); + public static readonly Color UnclearGlass = new(183, 183, 189); public static readonly Color DarkGrassColor = GrassColor.GetDark(); public static void AddToColorDictionary() diff --git a/src/Arquimedes/Settings/InputSetting.cs b/src/Arquimedes/Settings/InputSetting.cs new file mode 100644 index 00000000..695fe0f4 --- /dev/null +++ b/src/Arquimedes/Settings/InputSetting.cs @@ -0,0 +1,32 @@ +using Arquimedes.Enumerators; + +namespace Arquimedes.Settings +{ + public class InputSetting : IEquatable + { + public required KeymapAction Action { get; set; } + public required string[] Keys { get; set; } + public string Category { get; set; } = "Misc"; + public string[]? Modifier { get; set; } + + public bool Equals(InputSetting? other) + { + if (Action == other?.Action && Category.Equals(other.Category)) + return true; + + return false; + } + + public override bool Equals(object? obj) + { + if (obj is null) + return false; + return Equals(obj as InputSetting); + } + + public override int GetHashCode() + { + return HashCode.Combine(Action); + } + } +} diff --git a/src/Arquimedes/Settings/inputs_setting.json b/src/Arquimedes/Settings/inputs_setting.json new file mode 100644 index 00000000..3814d99b --- /dev/null +++ b/src/Arquimedes/Settings/inputs_setting.json @@ -0,0 +1,127 @@ +[ + { + "Keys": ["up_arrow", "numpad_8"], + "Action": "MoveNorth", + "Category": "Movement" + }, + { + "Keys": ["down_arrow", "numpad_2"], + "Action": "MoveSouth", + "Category": "Movement" + }, + { + "Keys": ["left_arrow", "numpad_4"], + "Action": "MoveLeft", + "Category": "Movement" + }, + { + "Keys": ["right_arrow", "numpad_6"], + "Action": "MoveRight", + "Category": "Movement" + }, + { + "Keys": ["numpad_7"], + "Action": "MoveNorthLeft", + "Category": "Movement" + }, + { + "Keys": ["numpad_9"], + "Action": "MoveNorthRight", + "Category": "Movement" + }, + { + "Keys": ["numpad_1"], + "Action": "MoveSouthLeft", + "Category": "Movement" + }, + { + "Keys": ["numpad_3"], + "Action": "MoveSouthRight", + "Category": "Movement" + }, + { + "Keys": ["i"], + "Action": "OpenInventory", + "Category": "Ui" + }, + { + "Keys": ["t"], + "Action": "ThownItem", + "Category": "Interaction" + }, + { + "Keys": ["esc"], + "Action": "EscapeMenu", + "Category": "Ui" + }, + { + "Keys": ["."], + "Action": "MoveDown", + "Category": "Movement", + "Modifier": ["Shift"] + }, + { + "Keys": [","], + "Action": "MoveUp", + "Category": "Movement", + "Modifier": ["Shift"] + }, + { + "Keys": ["numpad_5"], + "Action": "WaitTillRested", + "Category": "Misc", + "Modifier": ["Control"] + }, + { + "Keys": [".", "numpad_5"], + "Action": "WaitOneSecond", + "Category": "Misc" + }, + { + "Keys": [","], + "Action": "WaitOneMoment", + "Category": "Misc" + }, + { + "Keys": ["g"], + "Action": "PickUp", + "Category": "Interaction" + }, + { + "Keys": ["d"], + "Action": "DropItem", + "Category": "Interaction" + }, + { + "Keys": ["c"], + "Action": "CloseDoor", + "Category": "Interaction" + }, + { + "Keys": ["l"], + "Action": "Look", + "Category": "Ui" + }, + { + "Keys": ["z"], + "Action": "SpellCasting", + "Category": "Interaction", + "Modifier": ["Shift"] + }, + { + "Keys": ["r"], + "Action": "WaitScreen", + "Category": "Ui", + "Modifier": ["Shift"] + }, + { + "Keys": ["enter"], + "Action": "ConfirmAction", + "Category": "Ui" + }, + { + "Keys": ["esc"], + "Action": "CancelAction", + "Category": "Ui" + } +] diff --git a/src/Diviner/Diviner.csproj b/src/Diviner/Diviner.csproj index 03d9e894..9c6ca5e9 100644 --- a/src/Diviner/Diviner.csproj +++ b/src/Diviner/Diviner.csproj @@ -1,15 +1,16 @@ - net9.0 + net10.0 enable enable - - + + + diff --git a/src/Diviner/Extensions/KeyboardExtensions.cs b/src/Diviner/Extensions/KeyboardExtensions.cs new file mode 100644 index 00000000..e9444421 --- /dev/null +++ b/src/Diviner/Extensions/KeyboardExtensions.cs @@ -0,0 +1,179 @@ +using Arquimedes.Enumerators; +using Arquimedes.Settings; +using MagusEngine; +using SadConsole.Input; + +namespace Diviner.Extensions +{ + public static class KeyboardExtensions + { + private static readonly Dictionary _map = new(StringComparer.OrdinalIgnoreCase) + { + ["up_arrow"] = Keys.Up, + ["down_arrow"] = Keys.Down, + ["left_arrow"] = Keys.Left, + ["right_arrow"] = Keys.Right, + ["up"] = Keys.Up, + ["down"] = Keys.Down, + ["left"] = Keys.Left, + ["right"] = Keys.Right, + + ["enter"] = Keys.Enter, + ["return"] = Keys.Enter, + ["esc"] = Keys.Escape, + ["escape"] = Keys.Escape, + ["space"] = Keys.Space, + ["spacebar"] = Keys.Space, + ["tab"] = Keys.Tab, + ["backspace"] = Keys.Back, + ["capslock"] = Keys.CapsLock, + ["pause"] = Keys.Pause, + ["shift"] = Keys.LeftShift, + ["left_shift"] = Keys.LeftShift, + ["right_shift"] = Keys.RightShift, + ["ctrl"] = Keys.LeftControl, + ["control"] = Keys.LeftControl, + ["left_ctrl"] = Keys.LeftControl, + ["right_ctrl"] = Keys.RightControl, + ["alt"] = Keys.LeftAlt, + ["left_alt"] = Keys.LeftAlt, + ["right_alt"] = Keys.RightAlt, + + ["0"] = Keys.D0, + ["1"] = Keys.D1, + ["2"] = Keys.D2, + ["3"] = Keys.D3, + ["4"] = Keys.D4, + ["5"] = Keys.D5, + ["6"] = Keys.D6, + ["7"] = Keys.D7, + ["8"] = Keys.D8, + ["9"] = Keys.D9, + + ["a"] = Keys.A, + ["b"] = Keys.B, + ["c"] = Keys.C, + ["d"] = Keys.D, + ["e"] = Keys.E, + ["f"] = Keys.F, + ["g"] = Keys.G, + ["h"] = Keys.H, + ["i"] = Keys.I, + ["j"] = Keys.J, + ["k"] = Keys.K, + ["l"] = Keys.L, + ["m"] = Keys.M, + ["n"] = Keys.N, + ["o"] = Keys.O, + ["p"] = Keys.P, + ["q"] = Keys.Q, + ["r"] = Keys.R, + ["s"] = Keys.S, + ["t"] = Keys.T, + ["u"] = Keys.U, + ["v"] = Keys.V, + ["w"] = Keys.W, + ["x"] = Keys.X, + ["y"] = Keys.Y, + ["z"] = Keys.Z, + + ["numpad_0"] = Keys.NumPad0, + ["numpad_1"] = Keys.NumPad1, + ["numpad_2"] = Keys.NumPad2, + ["numpad_3"] = Keys.NumPad3, + ["numpad_4"] = Keys.NumPad4, + ["numpad_5"] = Keys.NumPad5, + ["numpad_6"] = Keys.NumPad6, + ["numpad_7"] = Keys.NumPad7, + ["numpad_8"] = Keys.NumPad8, + ["numpad_9"] = Keys.NumPad9, + ["numpad_add"] = Keys.Add, + ["numpad_subtract"] = Keys.Subtract, + ["numpad_multiply"] = Keys.Multiply, + ["numpad_divide"] = Keys.Divide, + ["numpad_decimal"] = Keys.Decimal, + + ["f1"] = Keys.F1, + ["f2"] = Keys.F2, + ["f3"] = Keys.F3, + ["f4"] = Keys.F4, + ["f5"] = Keys.F5, + ["f6"] = Keys.F6, + ["f7"] = Keys.F7, + ["f8"] = Keys.F8, + ["f9"] = Keys.F9, + ["f10"] = Keys.F10, + ["f11"] = Keys.F11, + ["f12"] = Keys.F12, + + ["pageup"] = Keys.PageUp, + ["pagedown"] = Keys.PageDown, + ["home"] = Keys.Home, + ["end"] = Keys.End, + ["insert"] = Keys.Insert, + ["delete"] = Keys.Delete, + + [";"] = Keys.OemSemicolon, + ["+"] = Keys.OemPlus, + [","] = Keys.OemComma, + ["-"] = Keys.OemMinus, + ["."] = Keys.OemPeriod, + ["/"] = Keys.OemQuestion, + ["`"] = Keys.OemTilde, + ["["] = Keys.OemOpenBrackets, + ["\\"] = Keys.OemPipe, + ["]"] = Keys.OemCloseBrackets, + ["'"] = Keys.OemQuotes, + ["backslash"] = Keys.OemBackslash, + + ["dot"] = Keys.OemPeriod, + ["comma"] = Keys.OemComma, + ["minus"] = Keys.OemMinus, + ["plus"] = Keys.OemPlus, + ["period"] = Keys.OemPeriod, + ["question"] = Keys.OemQuestion, + ["tilde"] = Keys.OemTilde, + ["bracket_left"] = Keys.OemOpenBrackets, + ["bracket_right"] = Keys.OemCloseBrackets, + ["quote"] = Keys.OemQuotes, + ["backslash_alt"] = Keys.OemBackslash + }; + + public static Keys GetKeyFromString(string str) + { + if (!_map.TryGetValue(str, out var key)) + return Keys.None; + return key; + } + + public static KeymapAction? GetActionFromKey(this Keyboard info) + { + var inputs = Locator.GetService>(); + + foreach (var key in info.KeysPressed) + { + var modifiers = info.KeysDown.Where(i => + i.Key == Keys.LeftShift || + i.Key == Keys.RightShift || + i.Key == Keys.LeftControl || + i.Key == Keys.RightControl || + i.Key == Keys.LeftAlt || + i.Key == Keys.RightAlt + ).Select(i => + { + var key = i.Key.ToString(); + if (key.Contains("shift", StringComparison.OrdinalIgnoreCase)) + return "Shift"; + if (key.Contains("control", StringComparison.OrdinalIgnoreCase)) + return "Control"; + return "Alt"; + }).ToArray(); + + if (!inputs.TryGetValue(new(key.Key, modifiers), out var input)) + break; + return input.Action; + } + return null; + } + } +} diff --git a/src/Diviner/InputKey.cs b/src/Diviner/InputKey.cs new file mode 100644 index 00000000..74852de0 --- /dev/null +++ b/src/Diviner/InputKey.cs @@ -0,0 +1,40 @@ +using System.Diagnostics.CodeAnalysis; +using SadConsole.Input; + +namespace Diviner +{ + public readonly struct InputKey(Keys key, string[] modifiers) : IEquatable + { + public Keys Key { get; } = key; + public string[] Modifiers { get; } = modifiers ?? []; + + public override int GetHashCode() + { + return HashCode.Combine(Key, string.Join(",", Modifiers)); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null) + return false; + return Equals((InputKey)obj); + } + + public bool Equals(InputKey o) + { + if (o.Key == Key && Modifiers.SequenceEqual(o.Modifiers)) + return true; + return false; + } + + public static bool operator ==(InputKey left, InputKey right) + { + return left.Equals(right); + } + + public static bool operator !=(InputKey left, InputKey right) + { + return !(left == right); + } + } +} diff --git a/src/Diviner/KeyboardHandle.cs b/src/Diviner/KeyboardHandle.cs index a70571cd..7449a29c 100644 --- a/src/Diviner/KeyboardHandle.cs +++ b/src/Diviner/KeyboardHandle.cs @@ -1,22 +1,20 @@ using System.Diagnostics.CodeAnalysis; using Arquimedes.Enumerators; +using Diviner.Extensions; using Diviner.Windows; using MagusEngine; using MagusEngine.Actions; +using MagusEngine.Actions.Interfaces; using MagusEngine.Bus.MapBus; using MagusEngine.Bus.UiBus; using MagusEngine.Components.EntityComponents; using MagusEngine.Components.EntityComponents.Ai; using MagusEngine.Core.Entities; -using MagusEngine.Core.Magic; using MagusEngine.Core.MapStuff; -using MagusEngine.Exceptions; using MagusEngine.Services; using MagusEngine.Systems; using MagusEngine.Systems.Time; -using MagusEngine.Utils.Extensions; using SadConsole.Input; -using SadRogue.Primitives; using Color = SadRogue.Primitives.Color; namespace Diviner @@ -26,317 +24,68 @@ public static class KeyboardHandle [NotNull] private static readonly Player _getPlayer = Find.Universe?.Player!; - [AllowNull] - private static Target? _targetCursor; - - private static readonly Dictionary _movementDirectionMapping = new() + private static readonly Dictionary> _actionFactory = new() { - { Keys.NumPad7, Direction.UpLeft }, { Keys.NumPad8, Direction.Up }, { Keys.NumPad9, Direction.UpRight }, - { Keys.NumPad4, Direction.Left }, { Keys.NumPad6, Direction.Right }, - { Keys.NumPad1, Direction.DownLeft }, { Keys.NumPad2, Direction.Down }, { Keys.NumPad3, Direction.DownRight }, - { Keys.Up, Direction.Up }, { Keys.Down, Direction.Down }, { Keys.Left, Direction.Left }, { Keys.Right, Direction.Right } + [KeymapAction.MoveNorth] = () => new MoveAction((0, -1)), + [KeymapAction.MoveSouth] = () => new MoveAction((0, 1)), + [KeymapAction.MoveLeft] = () => new MoveAction((-1, 0)), + [KeymapAction.MoveRight] = () => new MoveAction((1, 0)), + [KeymapAction.MoveNorthLeft] = () => new MoveAction((-1, -1)), + [KeymapAction.MoveNorthRight] = () => new MoveAction((1, -1)), + [KeymapAction.MoveSouthLeft] = () => new MoveAction((-1, 1)), + [KeymapAction.MoveSouthRight] = () => new MoveAction((1, 1)), + [KeymapAction.MoveUp] = () => new UpDownMovementAction(1), + [KeymapAction.MoveDown] = () => new UpDownMovementAction(-1), + [KeymapAction.OpenInventory] = () => new OpenInventoryAction(), + [KeymapAction.ThownItem] = () => new ThrowItemAction(), + [KeymapAction.EscapeMenu] = () => new EscapeMenuAction(), + [KeymapAction.WaitScreen] = () => new OpenWaitAction(), + [KeymapAction.WaitTillRested] = () => new RestAction(_getPlayer), + [KeymapAction.WaitOneMoment] = () => new WaitAction(TimeHelper.OneMoment), + [KeymapAction.WaitOneSecond] = () => new WaitAction(TimeHelper.OneSecond), + [KeymapAction.PickUp] = () => new PickUpPlayerAction(_getPlayer), + [KeymapAction.DropItem] = () => new DropItemPlayerAction(), + [KeymapAction.CloseDoor] = () => new OpenCloseDoorAction(_getPlayer, true), + [KeymapAction.OpenDoor] = () => new OpenCloseDoorAction(_getPlayer, false), + [KeymapAction.Look] = () => new LookAction(), + [KeymapAction.SpellCasting] = () => new SpellCastingPlayerAction(_getPlayer), + [KeymapAction.Interact] = () => new InteractAction(), + [KeymapAction.ConfirmAction] = () => new ConfirmAction(), + [KeymapAction.CancelAction] = () => new CancelAction(), }; - public static bool HandleMapKeys(Keyboard input, UIManager ui, Universe world) - { - return HandleActions(input, world, ui); - } - - public static bool HandleUiKeys(Keyboard info, UIManager ui) - { - if (info.IsKeyPressed(Keys.I)) - { - ui.InventoryScreen.ShowItems(_getPlayer); - return true; - } - - if (info.IsKeyPressed(Keys.T)) - { - ui.InventoryScreen.ShowItems(_getPlayer, item => - { - _targetCursor ??= new Target(_getPlayer.Position); - if (item is null) - { - Locator.GetService().SendMessage(new("No item selected!")); - return; - } - _targetCursor.OnSelectItem(item, _getPlayer); - ui.InventoryScreen.Hide(); - _getPlayer.Inventory.Remove(item); - }); - } - - if (info.IsKeyPressed(Keys.Escape) && ui.NoPopWindow) - { - ui.MainMenu.Show(); - ui.MainMenu.IsFocused = true; - return true; - } - - return false; - } - - private static bool HandleMove(Keyboard info, Universe world, UIManager ui) - { - #region WorldMovement - - if (CurrentMapIsPlanetView(world)) - { - var console = ui.MapWindow.MapConsole; - - if (info.IsKeyDown(Keys.Left)) - { - console.Surface.ViewPosition = console.Surface.ViewPosition.Translate((-1, 0)); - } - - if (info.IsKeyDown(Keys.Right)) - { - console.Surface.ViewPosition = console.Surface.ViewPosition.Translate((1, 0)); - } - - if (info.IsKeyDown(Keys.Up)) - { - console.Surface.ViewPosition = console.Surface.ViewPosition.Translate((0, -1)); - } - - if (info.IsKeyDown(Keys.Down)) - { - console.Surface.ViewPosition = console.Surface.ViewPosition.Translate((0, +1)); - } - // Must return false, because there isn't any movement of the actor - return false; - } - - #endregion WorldMovement - if (world.CurrentMap is null) - return false; - var key = _movementDirectionMapping.Keys.FirstOrDefault(info.IsKeyPressed); - if (_movementDirectionMapping.TryGetValue(key, out var moveDirection)) - { - Point deltaMove = new(moveDirection.DeltaX, moveDirection.DeltaY); - var actor = (Actor)world.CurrentMap.ControlledEntitiy!; - if (world.CurrentMap.ControlledEntitiy is not Player) - { - if (world.CurrentMap.CheckForIndexOutOfBounds(world.CurrentMap.ControlledEntitiy!.Position + deltaMove)) - return false; - - int distance = HandleNonPlayerMoveAndReturnDistance(world, deltaMove); - - return world.CurrentMap.PlayerExplored[world.CurrentMap.ControlledEntitiy.Position + deltaMove] - && distance <= _targetCursor?.MaxDistance - && actor!.MoveBy(deltaMove); - } - return actor!.MoveBy(deltaMove); - } - return false; - } - - private static int HandleNonPlayerMoveAndReturnDistance(Universe world, Point coorToMove) - { - int distance = 0; - _ = world.CurrentMap ?? throw new NullValueException(nameof(world.CurrentMap)); - - if (world.CurrentMap.ControlledEntitiy == _targetCursor?.Cursor) - { - _ = _targetCursor ?? throw new NullValueException(nameof(_targetCursor)); - - if (_targetCursor.TravelPath is not null) - distance = _targetCursor.TravelPath.LengthWithStart; - if (_targetCursor.TravelPath is not null && _targetCursor.TravelPath.LengthWithStart >= _targetCursor.MaxDistance) - { - distance = world!.CurrentMap!.AStar!.ShortestPath(_targetCursor.OriginCoord, world!.CurrentMap!.ControlledEntitiy!.Position + coorToMove)!.Length; - } - } - return distance; - } - private static bool HandleActions(Keyboard info, Universe uni, UIManager ui) + public static bool HandleKeys(Keyboard info) { - if (_getPlayer == null || uni == null) - return false; - - // Work around for a > symbol, must be top to not make the char wait - if (info.IsKeyDown(Keys.LeftShift) && info.IsKeyPressed(Keys.OemPeriod)) - { - return ActionManager.EnterDownMovement(_getPlayer.Position); - } - // Work around for a < symbol, must be top to not make the char wait - if (info.IsKeyDown(Keys.LeftShift) && info.IsKeyPressed(Keys.OemComma)) - { - return ActionManager.EnterUpMovement(_getPlayer.Position); - } - if (HandleMove(info, uni, ui)) - { - if (!_getPlayer.Bumped && uni?.CurrentMap?.ControlledEntitiy is Player) - { - Locator.GetService().SendMessage(new(TimeHelper.GetWalkTime(_getPlayer, - uni.CurrentMap.GetTileAt(_getPlayer.Position)!), true)); - } - else if (uni?.CurrentMap?.ControlledEntitiy is Player) - { - var attack = _getPlayer.GetAttacks().GetRandomItemFromList() ?? throw new NullValueException("Attack was null", null); - Locator.GetService().SendMessage(new(TimeHelper.GetAttackTime(_getPlayer, attack), true)); - } - - return true; - } - - if (info.IsKeyPressed(Keys.NumPad5) && info.IsKeyDown(Keys.LeftControl)) - { - return ActionManager.RestTillFull(_getPlayer); - } - - if (info.IsKeyPressed(Keys.NumPad5) || info.IsKeyPressed(Keys.OemPeriod)) - { - Locator.GetService().SendMessage(new(TimeHelper.Wait, true)); - return true; - } - - if (info.IsKeyPressed(Keys.OemComma)) - { - Locator.GetService().SendMessage(new(10, true)); - return true; - } - - //if (info.IsKeyPressed(Keys.A)) - //{ - // bool sucess = ActionManager.DirectAttack(world.Player); - // world.ProcessTurn(TimeHelper.GetAttackTime(world.Player), sucess); - // return sucess; - //} // some other thing will be in here! - if (info.IsKeyPressed(Keys.G)) - { - Item item = uni.CurrentMap!.GetEntityAt(uni.CurrentMap.ControlledEntitiy!.Position)!; - bool sucess = ActionManager.PickUp(uni.Player, item!); - Locator.GetService().SendMessage(new(TimeHelper.Interact, sucess)); - return sucess; - } - - if (info.IsKeyPressed(Keys.D)) - { - //bool sucess = ActionManager.DropTopItemInv(uni.Player); - ui.InventoryScreen.ShowItems((Actor)uni!.CurrentMap!.ControlledEntitiy!, item => - { - var sucess = ActionManager.DropItem(item, _getPlayer.Position, uni.CurrentMap); - Locator.GetService().SendMessage(new(TimeHelper.Interact, sucess)); - }); + var action = info.GetActionFromKey(); + if (action is null) return false; - } - if (info.IsKeyPressed(Keys.C)) - { - bool sucess = ActionManager.CloseDoor(uni.Player); - Locator.GetService().SendMessage(new(TimeHelper.Interact, sucess)); - ui.MapWindow.MapConsole.IsDirty = true; - } - if (info.IsKeyDown(Keys.LeftShift) && info.IsKeyPressed(Keys.H)) - { - bool sucess = ActionManager.NodeDrain(_getPlayer); - Locator.GetService().SendMessage(new(TimeHelper.MagicalThings, sucess)); - } - if (info.IsKeyPressed(Keys.L)) - { - _targetCursor ??= new Target(_getPlayer.Position); - - if (_targetCursor.State == TargetState.LookMode) - { - _targetCursor.EndTargetting(); - } - else - { - _targetCursor.StartTargetting(); - } - - return true; - } - - if (info.IsKeyDown(Keys.LeftShift) && info.IsKeyPressed(Keys.Z)) - { - SpellSelectWindow spell = new(_getPlayer.Soul.CurrentMana); - - _targetCursor ??= new Target(_getPlayer.Position); - var magic = _getPlayer.GetComponent(); - spell.Show(magic.KnowSpells, selectedSpell => _targetCursor.OnSelectSpell(selectedSpell, (Actor)uni.CurrentMap!.ControlledEntitiy!), _getPlayer.Soul.CurrentMana); - - return true; - } - - if (info.IsKeyDown(Keys.LeftShift) && info.IsKeyPressed(Keys.R)) - { - var wait = ui.GetWindow(WindowTag.Wait); - if (wait is null) - { - wait = new(); - ui.AddWindowToList(wait); - } - wait.Show(true); - return true; - } - - if (info.IsKeyPressed(Keys.Enter) && _targetCursor is not null) - { - if (_targetCursor.AnyTargeted()) - { - bool sucess = false; - long timeTaken = 0; - if (_targetCursor.State == TargetState.LookMode) - { - _targetCursor.LookTarget(); - return true; - } - else if (_targetCursor.State == TargetState.TargetingSpell) - { - (sucess, var spellCasted) = _targetCursor.EndSpellTargetting(); - if (sucess) - timeTaken = TimeHelper.GetCastingTime(_getPlayer, spellCasted!); - } - else - { - (sucess, var item) = _targetCursor.EndItemTargetting(); - if (sucess) - timeTaken = TimeHelper.GetShootingTime(_getPlayer, item!.Mass); - } - if (sucess) - { - _targetCursor = null; - Locator.GetService()?.SendMessage(new(timeTaken, sucess)); - } - - return sucess; - } - else - { - Locator.GetService()?.SendMessage(new("Invalid target!")); - return false; - } - } - - if (info.IsKeyPressed(Keys.Escape) && (_targetCursor is not null)) - { - _targetCursor.EndTargetting(); - - _targetCursor = null!; - - return true; - } - #if DEBUG - if (HandleDebugActions(info, uni, ui)) + if (HandleDebugActions(info, Find.Universe)) { return true; } #endif + var executeAction = GetExecuteAction(action.Value); + if (executeAction is null) + return false; + return executeAction.Execute(Find.Universe); + } - return false; + private static IExecuteAction? GetExecuteAction(KeymapAction action) + { + if (_actionFactory.TryGetValue(action, out var factory)) + return factory(); + return null; } #if DEBUG - private static bool HandleDebugActions(Keyboard info, Universe uni, UIManager ui) + private static bool HandleDebugActions(Keyboard info, Universe uni) { if (info.IsKeyPressed(Keys.F10)) { ActionManager.ToggleFOV(); - ui.MapWindow.MapConsole.IsDirty = true; int c = uni!.CurrentMap!.PlayerExplored.Count; for (int i = 0; i < c; i++) { @@ -350,10 +99,10 @@ private static bool HandleDebugActions(Keyboard info, Universe uni, UIManager ui uni!.CurrentMap!.ForceFovCalculation(); return false; } - - if (info.IsKeyPressed(Keys.K) && _targetCursor?.TileInTarget() == true) + var targetCursor = uni.CurrentMap.TargetCursor; + if (info.IsKeyPressed(Keys.K) && targetCursor?.TileInTarget() == true) { - Tile tile = uni!.CurrentMap!.GetTileAt(_targetCursor.Position)!; + Tile tile = uni!.CurrentMap!.GetTileAt(targetCursor.Position)!; tile!.IsTransparent = !tile.IsTransparent; return false; } @@ -403,23 +152,23 @@ private static bool HandleDebugActions(Keyboard info, Universe uni, UIManager ui if (info.IsKeyDown(Keys.LeftControl) && info.IsKeyDown(Keys.LeftShift) - && info.IsKeyPressed(Keys.O) && _targetCursor is not null) + && info.IsKeyPressed(Keys.O) && targetCursor is not null) { - var (_, actor) = ActionManager.CreateTestEntity(_targetCursor.Cursor.Position, uni); + var (_, actor) = ActionManager.CreateTestEntity(targetCursor.Cursor.Position, uni); actor.AddComponents(new MoveAndAttackAI(actor.GetViewRadius())); return false; } - if (info.IsKeyDown(Keys.LeftShift) && info.IsKeyPressed(Keys.O) && _targetCursor is not null) + if (info.IsKeyDown(Keys.LeftShift) && info.IsKeyPressed(Keys.O) && targetCursor is not null) { - var (_, entity) = ActionManager.CreateTestEntity(_targetCursor.Cursor.Position, uni); + var (_, entity) = ActionManager.CreateTestEntity(targetCursor.Cursor.Position, uni); entity.AddComponents(new BasicAi(entity)); return false; } - if (info.IsKeyDown(Keys.LeftShift) && info.IsKeyPressed(Keys.P) && _targetCursor!.EntityInTarget()) + if (info.IsKeyDown(Keys.LeftShift) && info.IsKeyPressed(Keys.P) && targetCursor!.EntityInTarget()) { - Actor actor = (Actor)_targetCursor.TargetEntity()!; + Actor actor = (Actor)targetCursor.TargetEntity()!; actor.AddComponents(new MoveAndAttackAI(actor.GetViewRadius())); Locator.GetService() .SendMessage(new($"Added attack component to {actor.Name}!")); @@ -429,9 +178,9 @@ private static bool HandleDebugActions(Keyboard info, Universe uni, UIManager ui if (info.IsKeyDown(Keys.LeftShift) && info.IsKeyDown(Keys.LeftControl) && info.IsKeyPressed(Keys.P) - && _targetCursor!.EntityInTarget()) + && targetCursor!.EntityInTarget()) { - Actor? actor = (Actor?)_targetCursor.TargetEntity(); + Actor? actor = (Actor?)targetCursor.TargetEntity(); actor?.AddComponents(new NeedDrivenAi()); Locator.GetService() .SendMessage(new($"Added need component to {actor?.Name}!")); @@ -444,9 +193,9 @@ private static bool HandleDebugActions(Keyboard info, Universe uni, UIManager ui return false; } - if (info.IsKeyPressed(Keys.P) && (_targetCursor?.EntityInTarget()) == true) + if (info.IsKeyPressed(Keys.P) && (targetCursor?.EntityInTarget()) == true) { - var target = _targetCursor.TargetEntity(); + var target = targetCursor.TargetEntity(); var needs = target!.GetComponent(); for (int i = 0; i < needs.Count; i++) { @@ -464,8 +213,5 @@ private static bool HandleDebugActions(Keyboard info, Universe uni, UIManager ui } #endif - - private static bool CurrentMapIsPlanetView(Universe world) => - world.WorldMap != null && world.WorldMap.AssocietatedMap == world.CurrentMap && world.Player == null; } } diff --git a/src/Diviner/UIManager.cs b/src/Diviner/UIManager.cs index 136760a5..6620d6f2 100644 --- a/src/Diviner/UIManager.cs +++ b/src/Diviner/UIManager.cs @@ -6,15 +6,16 @@ using Diviner.Windows; using GoRogue.Messaging; using MagusEngine; -using MagusEngine.Exceptions; using MagusEngine.Bus; using MagusEngine.Bus.UiBus; using MagusEngine.Core.Entities; +using MagusEngine.Exceptions; using MagusEngine.Services; using MagusEngine.Systems; using MagusEngine.Utils; using SadConsole; using SadConsole.Input; +using SadConsole.Instructions; using Color = SadConsole.UI.AdjustableColor; namespace Diviner @@ -27,7 +28,12 @@ public sealed class UIManager : ScreenObject, ISubscriber, ISubscriber, ISubscriber, - ISubscriber + ISubscriber, + ISubscriber, + ISubscriber, + ISubscriber, + ISubscriber, + ISubscriber { private readonly Dictionary _windows = []; private Universe? _universe; @@ -115,7 +121,7 @@ private void ConfigureWindowsAndConsoles(int height, int width, Universe uni) #endif // Inventory initialization InventoryScreen = new InventoryWindow(width / 2, height / 2); - Children.Add(InventoryScreen); + AddWindowToList(InventoryScreen); InventoryScreen.Hide(); const int statusWindowHeight = 4; StatusWindow = new BottomStatusWindow(width - MessageLog.Width, statusWindowHeight, "Status Window"); @@ -168,11 +174,7 @@ public override bool ProcessKeyboard(Keyboard info) && (_universe.CurrentMap.ControlledEntitiy is not null || _universe.WorldMap.AssocietatedMap.Equals(_universe.CurrentMap))) { - if (KeyboardHandle.HandleMapKeys(info, this, _universe)) - { - return true; - } - if (KeyboardHandle.HandleUiKeys(info, this)) + if (KeyboardHandle.HandleKeys(info)) { return true; } @@ -291,6 +293,46 @@ public void Handle([NotNull] ShowGlyphOnConsole message) message.LastUsedGlyph = originalGlyph; } + public void Handle(CloseWindowMessage message) + { + MagiBaseWindow window = GetWindow(message.Tag) ?? throw new NullValueException(nameof(window)); + window.Hide(); + } + + public void Handle(ShowMainMenuMessage message) + { + if (!NoPopWindow) + return; + MainMenu.Show(); + MainMenu.IsFocused = true; + } + + public void Handle(ScrollConsoleMessage message) + { + var console = MapWindow.MapConsole; + console.Surface.ViewPosition = console.Surface.ViewPosition.Translate(message.Delta); + } + + public void Handle(OpenWindowEvent message) + { + var window = GetWindow(message.Window); + if (window is null) + throw new NullValueException(nameof(window)); + if (window is WaitWindow) + { + window = new WaitWindow(); + AddWindowToList(window); + } + window?.Show(true); + } + + public void Handle(OpenSpellCastingWindowMessage message) + { + SpellSelectWindow spell = new(message.CurrentMana); + + spell.Show(message.Spells, message.OnCast!, message.CurrentMana); + } + ~UIManager() { Locator.GetService().UnRegisterAllSubscriber(this); diff --git a/src/Diviner/Windows/InventoryWindow.cs b/src/Diviner/Windows/InventoryWindow.cs index 6bbb23b2..1a32e156 100644 --- a/src/Diviner/Windows/InventoryWindow.cs +++ b/src/Diviner/Windows/InventoryWindow.cs @@ -1,4 +1,9 @@ -using MagusEngine.Core.Entities; +using Arquimedes.Enumerators; +using GoRogue.Messaging; +using MagusEngine; +using MagusEngine.Bus.UiBus; +using MagusEngine.Core.Entities; +using MagusEngine.Services; using MagusEngine.Utils.Extensions; using SadConsole; using SadConsole.Input; @@ -8,8 +13,9 @@ namespace Diviner.Windows { - public class InventoryWindow : PopWindow + public class InventoryWindow : PopWindow, ISubscriber { + private readonly MessageBusService _bus; // Create the field private readonly Console inventoryConsole; @@ -22,6 +28,7 @@ public class InventoryWindow : PopWindow /// public InventoryWindow(int width, int heigth, string title = "Inventory") : base(title) { + _bus = Locator.GetService(); // define the inventory console inventoryConsole = new Console(width - WindowBorderThickness, heigth - WindowBorderThickness) { @@ -36,6 +43,8 @@ public InventoryWindow(int width, int heigth, string title = "Inventory") : base invScrollBar.ValueChanged += InvScrollBar_ValueChanged; Controls.Add(invScrollBar); + _bus.RegisterAllSubscriber(this); + Tag = WindowTag.Inv; } public override bool ProcessKeyboard(Keyboard info) @@ -87,5 +96,15 @@ private void RefreshControls(Actor actorInventory, Action? itemAction) SetupSelectionButtons(BuildHotKeysButtons(actorInventory.Inventory, itemAction ?? OnItemSelected)); _actionContext = itemAction; } + + public void Handle(InventoryActionBus message) + { + ShowItems(message.ActorInventory, message.Action); + } + + ~InventoryWindow() + { + _bus.UnRegisterAllSubscriber(this); + } } } diff --git a/src/Diviner/Windows/MainMenuWindow.cs b/src/Diviner/Windows/MainMenuWindow.cs index b9bd8fcd..05093a17 100644 --- a/src/Diviner/Windows/MainMenuWindow.cs +++ b/src/Diviner/Windows/MainMenuWindow.cs @@ -1,6 +1,5 @@ using Arquimedes.Utils; using Diviner.Controls; -using GoRogue.Messaging; using MagusEngine; using MagusEngine.Bus; using MagusEngine.Bus.UiBus; @@ -12,8 +11,7 @@ namespace Diviner.Windows { - public class MainMenuWindow : MagiBaseWindow, - ISubscriber + public class MainMenuWindow : MagiBaseWindow { private readonly MagiButton startGame; private readonly MagiButton testMap; @@ -21,6 +19,7 @@ public class MainMenuWindow : MagiBaseWindow, private readonly MagiButton saveGame; // neither does this private ListBox? savesBox; private PopWindow? loadPop; + public bool GameStarted { get; set; } public MainMenuWindow(int width, int height, string title = "Main Menu") : base(width, height, title) @@ -38,7 +37,7 @@ public MainMenuWindow(int width, int height, string title = "Main Menu") : base( { Text = "Test Map" }; - MagiButton quitGame = new MagiButton(11, 1) + MagiButton quitGame = new(11, 1) { Text = "Quit Game" }; @@ -76,7 +75,7 @@ private void ContinueGame_Click(object? sender, EventArgs e) loadPop = new PopWindow(30, 15, "Load Game"); const string text = "Load!"; // The load button - MagiButton loadGame = new MagiButton(text.Length + 2) + MagiButton loadGame = new(text.Length + 2) { Text = text, Position = new Point(3, loadPop.Height - 2) @@ -90,7 +89,7 @@ private void ContinueGame_Click(object? sender, EventArgs e) Position = new Point((loadPop.Width / 2) - 10, (loadPop.Height / 2) - 5) }; const string delete = "Delete"; - MagiButton deleteSaveBtn = new MagiButton(delete.Length + 2) + MagiButton deleteSaveBtn = new(delete.Length + 2) { Text = delete, Position = new Point((loadPop.Width / 2) - 5, loadPop.Height - 3) @@ -113,10 +112,10 @@ private void ContinueGame_Click(object? sender, EventArgs e) private void DeleteSaveBtn_Click(object? sender, EventArgs e) { - if (savesBox.SelectedItem != null) + if (savesBox?.SelectedItem != null) { - SavingService.DeleteSave(savesBox.SelectedItem?.ToString()); - savesBox.Items.Remove(savesBox.SelectedItem); + SavingService.DeleteSave(savesBox.SelectedItem?.ToString()!); + savesBox.Items.Remove(savesBox.SelectedItem!); savesBox.IsDirty = true; } } @@ -124,10 +123,10 @@ private void DeleteSaveBtn_Click(object? sender, EventArgs e) private void LoadGame_Click(object? sender, EventArgs e) { if (savesBox?.SelectedItem != null - && SavingService.CheckIfStringIsValidSave(savesBox.SelectedItem.ToString())) + && SavingService.CheckIfStringIsValidSave(savesBox.SelectedItem.ToString()!)) { - loadPop.Hide(); - Universe uni = SavingService.LoadGame(savesBox.SelectedItem.ToString()); + loadPop?.Hide(); + Universe uni = SavingService.LoadGame(savesBox.SelectedItem.ToString()!); Locator.GetService().SendMessage(new(uni.Player, uni)); } } @@ -141,7 +140,7 @@ private void PopulateListWithSaves() for (int i = 0; i < saves.Length; i++) { string save = SaveUtils.GetSaveName(saves[i]); - savesBox.Items.Add(save); + savesBox?.Items?.Add(save); } } @@ -189,7 +188,7 @@ private void SaveGameClick(object? sender, EventArgs e) { // makes so that there can only be one save per player name! Find.Universe.SaveGame(Find.Universe.Player.Name); - PopWindow alert = new PopWindow(30, 10, "Save Done!"); + PopWindow alert = new(30, 10, "Save Done!"); // makes it a variable so that it can be properly accounted for in the print command const string text = "Save Sucessful!"; alert.Print((alert.Width - text.Length) / 2, 3, text); @@ -211,26 +210,6 @@ public void RestartGame() GameStarted = false; Find.Universe = null!; RefreshButtons(); - - //foreach (SadConsole.Console item in GameLoop.UIManager.Children.Cast()) - //{ - // if (!item.Equals(this)) - // item.Dispose(); - //} - - //GameLoop.UIManager.MessageLog = null!; - //GameLoop.UIManager.MapWindow = null!; - //GameLoop.UIManager.StatusWindow = null!; - //GameLoop.UIManager.InventoryScreen = null!; - //GameLoop.UIManager.CharCreationWindow = null!; - //GameLoop.UIManager.Children.Clear(); - //GameLoop.UIManager.Children.Add(this); - - Show(); - } - - public void Handle(ShowMainMenuMessage message) - { Show(); } } diff --git a/src/Diviner/Windows/MapWindow.cs b/src/Diviner/Windows/MapWindow.cs index 03d90e25..c5d0fe93 100644 --- a/src/Diviner/Windows/MapWindow.cs +++ b/src/Diviner/Windows/MapWindow.cs @@ -1,5 +1,4 @@ using Arquimedes.Enumerators; -using Diviner.Interfaces; using GoRogue.Messaging; using MagusEngine; using MagusEngine.Bus.UiBus; diff --git a/src/Diviner/Windows/PopWindow.cs b/src/Diviner/Windows/PopWindow.cs index f814af66..f62063ee 100644 --- a/src/Diviner/Windows/PopWindow.cs +++ b/src/Diviner/Windows/PopWindow.cs @@ -112,6 +112,7 @@ protected List BuildHotKeysButtons(List listItems, }; _hotKeys.Add(hotkeyLetter, (item, button.IsEnabled)); button.Click += (_, __) => button.Action.Invoke(); + button.Focused += (_, __) => button.Action.Invoke(); controlList.Add(button); } diff --git a/src/Diviner/Windows/SpellSelectWindow.cs b/src/Diviner/Windows/SpellSelectWindow.cs index 2973e422..e118d0d5 100644 --- a/src/Diviner/Windows/SpellSelectWindow.cs +++ b/src/Diviner/Windows/SpellSelectWindow.cs @@ -29,8 +29,7 @@ public SpellSelectWindow(double currentMana) : base("Select your spell") }; _castButton.Click += (_, __) => { - _onCast?.Invoke(_selectedSpell!); - Hide(); + CastSpell(_selectedSpell!); }; } @@ -38,10 +37,14 @@ public override bool ProcessKeyboard(Keyboard info) { foreach (var key in info.KeysPressed) { + if (key.Key == Keys.Enter && _selectedSpell is not null) + { + CastSpell(_selectedSpell); + return true; + } if (_hotKeys.TryGetValue(key.Character, out var tuple) && tuple.Item2) { - _onCast((Spell)tuple.Item1); - Hide(); + CastSpell((Spell)tuple.Item1); return true; } @@ -49,6 +52,12 @@ public override bool ProcessKeyboard(Keyboard info) return base.ProcessKeyboard(info); } + private void CastSpell(Spell spell) + { + _onCast(spell); + Hide(); + } + public void Show(List listSpells, Action onCast, double currentMana) { _currentMana = currentMana; diff --git a/src/MagiRogue.Benchmarks/MagiRogue.Benchmarks.csproj b/src/MagiRogue.Benchmarks/MagiRogue.Benchmarks.csproj index 6044c251..657e8804 100644 --- a/src/MagiRogue.Benchmarks/MagiRogue.Benchmarks.csproj +++ b/src/MagiRogue.Benchmarks/MagiRogue.Benchmarks.csproj @@ -2,14 +2,14 @@ Exe - net9.0 + net10.0 enable enable - + diff --git a/src/MagiRogue.LegendsConsoleViewer/MagiRogue.LegendsConsoleViewer.csproj b/src/MagiRogue.LegendsConsoleViewer/MagiRogue.LegendsConsoleViewer.csproj index 194ca548..2fcbda60 100644 --- a/src/MagiRogue.LegendsConsoleViewer/MagiRogue.LegendsConsoleViewer.csproj +++ b/src/MagiRogue.LegendsConsoleViewer/MagiRogue.LegendsConsoleViewer.csproj @@ -2,7 +2,7 @@ Exe - net9.0 + net10.0 enable enable diff --git a/src/MagiRogue.Test/MagiRogue.Test.csproj b/src/MagiRogue.Test/MagiRogue.Test.csproj index b03ddfb3..2ffd299b 100644 --- a/src/MagiRogue.Test/MagiRogue.Test.csproj +++ b/src/MagiRogue.Test/MagiRogue.Test.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 false Library diff --git a/src/MagiRogue/MagiRogue.csproj b/src/MagiRogue/MagiRogue.csproj index 78f364aa..02f977bf 100644 --- a/src/MagiRogue/MagiRogue.csproj +++ b/src/MagiRogue/MagiRogue.csproj @@ -1,61 +1,57 @@ - + - - Exe - net9.0 - MagiRogue.GameLoop - false - Sofistico - Sofistico - - A roguelike created with SadConsole 9.x and GoRogue 3.x - - Wizard.ico - enable - True - Sofistico - README.md - - C:\Users\joaorodrigues\source\repos\MagiRogue\LICENSE - - + + Exe + net10.0 + false + Sofistico + Sofistico + + A roguelike created with SadConsole 9.x and GoRogue 3.x + + Wizard.ico + enable + True + Sofistico + README.md + + C:\Users\joaorodrigues\source\repos\MagiRogue\LICENSE + + - - 1701;1702;8765;8618;8604;8602;8600;8603 - + + 1701;1702;8765;8618;8604;8602;8600;8603 + - - 1701;1702;8765;8618;8604;8602;8600;8603 - + + 1701;1702;8765;8618;8604;8602;8600;8603 + - - - - - - + + + + + + - - - True - \ - - - - PreserveNewest - - - + + + True + \ + + + + PreserveNewest + + + - - - - - - - + + + + - - - + + + diff --git a/src/MagiRogue/GameLoop.cs b/src/MagiRogue/Program.cs similarity index 77% rename from src/MagiRogue/GameLoop.cs rename to src/MagiRogue/Program.cs index d0148bd0..5f932ce3 100644 --- a/src/MagiRogue/GameLoop.cs +++ b/src/MagiRogue/Program.cs @@ -1,18 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Linq; using Arquimedes; using Arquimedes.Settings; using Arquimedes.Utils; using Diviner; +using Diviner.Extensions; using MagusEngine; using MagusEngine.Services; using SadConsole; using SadConsole.Configuration; using SadConsole.Input; -using System; -using System.IO; +using SadConsole.UI.Windows; namespace MagiRogue { - public static class GameLoop + public static class Program { private static GlobalSettings settings; private static bool beginTest; @@ -63,7 +68,6 @@ private static void ConfigureBeforeCreateGame(string[] args) { foreach (var arg in args) { - // TODO! if (arg.Equals("test", StringComparison.Ordinal)) beginTest = true; } @@ -77,6 +81,24 @@ private static void ConfigureBeforeCreateGame(string[] args) settings = JsonUtils.JsonDeseralize(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Settings", "global_setting.json"))!; Locator.AddService(settings); + + ConfigureKeys(); + } + + private static void ConfigureKeys() + { + var listInputs = JsonUtils.JsonDeseralize>(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Settings", "inputs_setting.json"))!; + var dictInput = new Dictionary(listInputs.Count); + foreach (var input in listInputs) + { + foreach (var key in input.Keys) + { + var keyEnum = KeyboardExtensions.GetKeyFromString(key); + var inputKey = new InputKey(keyEnum, input.Modifier); + dictInput.TryAdd(inputKey, input); + } + } + Locator.AddService(dictInput); } private static void Init(object? sender, GameHost e) @@ -92,6 +114,9 @@ private static void Init(object? sender, GameHost e) // Now let the UIManager create its consoles so they can use the World data ui.InitMainMenu(GameHeight, GameWidth, beginTest); Locator.AddService(ui); +#if DEBUG + GlyphSelectPopup.AddRootComponent(Keys.F11); +#endif } #endregion configuration diff --git a/src/MagusEngine/Actions/ActionManager.cs b/src/MagusEngine/Actions/ActionManager.cs index 3d69c6fe..4ee9ee94 100644 --- a/src/MagusEngine/Actions/ActionManager.cs +++ b/src/MagusEngine/Actions/ActionManager.cs @@ -27,6 +27,7 @@ using System.Linq; using System.Text; using MagiMap = MagusEngine.Core.MapStuff.MagiMap; +using System; namespace MagusEngine.Actions { @@ -79,7 +80,7 @@ public static long MeleeAttack(Actor attacker, .SendMessage(new($"You are too tired to attack|{attacker.Name} is too tired to attack!", showMessage, isPlayer ? PointOfView.First : PointOfView.Third)); - return TimeHelper.Wait; + return TimeHelper.OneSecond; } // Create two messages that describe the outcome of the attack and defense @@ -112,12 +113,27 @@ public static long MeleeAttack(Actor attacker, attack, itemUsed, limbAttacking); - var staminaDiscount = attacker.Body.Stamina - - attack.PrepareVelocity * 10 + attacker.Body.Endurance * 0.5; - // discount stamina from the attacker - attacker.Body.Stamina = MathMagi.Round(staminaDiscount); - return TimeHelper.GetAttackTime(attacker, attack); + // Improved stamina cost calculation + var staminaCost = CalculateStaminaCost(attacker, attack, itemUsed); + attacker.Body.Stamina = Math.Max(0, attacker.Body.Stamina - staminaCost); + + return itemUsed != null ? + TimeHelper.GetAttackTimeWithWeapon(attacker, attack, itemUsed) : + TimeHelper.GetAttackTime(attacker, attack); + } + + /// + /// Calculates realistic stamina cost for attacks based on weapon weight, strength, and endurance + /// + private static double CalculateStaminaCost(Actor attacker, Attack attack, Item? weapon) + { + double baseCost = attack.PrepareVelocity; + double weaponWeight = weapon?.Mass ?? 1.0; + double strengthFactor = Math.Max(0.1, 1.0 - (attacker.GetStrenght() * 0.01)); + double enduranceFactor = Math.Max(0.5, 1.0 - (attacker.Body.Endurance * 0.005)); + + return baseCost * weaponWeight * strengthFactor * enduranceFactor; } public static void ShootProjectileAction(Point origin, @@ -358,34 +374,6 @@ public static (bool, Actor) CreateTestEntity(Point pos, Universe universe) // return false; //} - public static bool RestTillFull(Actor actor) - { - Body bodyStats = actor.Body; - //Mind mindStats = actor.Mind; - Soul soulStats = actor.Soul; - - if (bodyStats.Stamina < bodyStats.MaxStamina || soulStats.CurrentMana < soulStats.MaxMana) - { - // calculate here the amount of time that it will take in turns to rest to full - double staminaDif, manaDif; - - staminaDif = MathMagi.Round((bodyStats.MaxStamina - bodyStats.Stamina) / actor.GetStaminaRegen()); - manaDif = MathMagi.Round((soulStats.MaxMana - soulStats.CurrentMana) / actor.GetManaRegen()); - - double totalTurnsWait = staminaDif + manaDif; - - bool sus = WaitForNTurns((int)totalTurnsWait, actor); - - Locator.GetService().SendMessage(new($"You have rested for {totalTurnsWait} turns")); - - return sus; - } - - Locator.GetService().SendMessage(new("You have no need to rest")); - - return false; - } - /// /// Equips an item /// @@ -543,7 +531,7 @@ public static bool WaitForNTurns(int turns, Actor actor, bool canBeInterrupted = } } - Locator.GetService().SendMessage(new(TimeHelper.Wait, true)); + Locator.GetService().SendMessage(new(TimeHelper.OneSecond, true)); } return true; } diff --git a/src/MagusEngine/Actions/CancelAction.cs b/src/MagusEngine/Actions/CancelAction.cs new file mode 100644 index 00000000..133658e6 --- /dev/null +++ b/src/MagusEngine/Actions/CancelAction.cs @@ -0,0 +1,18 @@ +using MagusEngine.Actions.Interfaces; +using MagusEngine.Systems; + +namespace MagusEngine.Actions +{ + public class CancelAction : IExecuteAction + { + public bool Execute(Universe world) + { + var targetCursor = world?.CurrentMap?.TargetCursor; + targetCursor?.EndTargetting(); + + world?.CurrentMap?.TargetCursor = null; + + return true; + } + } +} diff --git a/src/MagusEngine/Actions/ConfirmAction.cs b/src/MagusEngine/Actions/ConfirmAction.cs new file mode 100644 index 00000000..08a76abc --- /dev/null +++ b/src/MagusEngine/Actions/ConfirmAction.cs @@ -0,0 +1,62 @@ +using Arquimedes.Enumerators; +using MagusEngine.Actions.Interfaces; +using MagusEngine.Bus.MapBus; +using MagusEngine.Bus.UiBus; +using MagusEngine.Core.Entities; +using MagusEngine.Services; +using MagusEngine.Systems; +using MagusEngine.Systems.Time; + +namespace MagusEngine.Actions +{ + public class ConfirmAction : IExecuteAction + { + private readonly MessageBusService _bus; + + public ConfirmAction() + { + _bus = Locator.GetService(); + } + + public bool Execute(Universe world) + { + var targetCursor = world?.CurrentMap?.TargetCursor; + Actor getPlayer = world!.Player!; + if (targetCursor?.AnyTargeted() == true) + { + long timeTaken = 0; + bool sucess; + if (targetCursor.State == TargetState.LookMode) + { + targetCursor.LookTarget(); + return true; + } + else if (targetCursor.State == TargetState.TargetingSpell) + { + (sucess, var spellCasted) = targetCursor.EndSpellTargetting(); + if (sucess) + timeTaken = TimeHelper.GetCastingTime(getPlayer, spellCasted!); + } + else + { + (sucess, var item) = targetCursor.EndItemTargetting(); + if (sucess) + timeTaken = TimeHelper.GetShootingTime(getPlayer, item!.Mass); + } + if (sucess) + { + world?.CurrentMap?.TargetCursor = null; + _bus.SendMessage(new(timeTaken, sucess)); + } + + return sucess; + } + else + { + _bus.SendMessage(new("Invalid target!")); + return false; + } + } + } +} + diff --git a/src/MagusEngine/Actions/DropItemPlayerAction.cs b/src/MagusEngine/Actions/DropItemPlayerAction.cs new file mode 100644 index 00000000..096d15e7 --- /dev/null +++ b/src/MagusEngine/Actions/DropItemPlayerAction.cs @@ -0,0 +1,31 @@ +using MagusEngine.Actions.Interfaces; +using MagusEngine.Bus.MapBus; +using MagusEngine.Bus.UiBus; +using MagusEngine.Core.Entities; +using MagusEngine.Services; +using MagusEngine.Systems; +using MagusEngine.Systems.Time; + +namespace MagusEngine.Actions +{ + public class DropItemPlayerAction : IExecuteAction + { + private readonly MessageBusService _bus; + + public DropItemPlayerAction() + { + _bus = Locator.GetService(); + } + + public bool Execute(Universe world) + { + var controlledActor = (Actor)world!.CurrentMap!.ControlledEntitiy!; + _bus.SendMessage(new(controlledActor, item => + { + var sucess = ActionManager.DropItem(item, controlledActor.Position, world.CurrentMap); + Locator.GetService().SendMessage(new(TimeHelper.Interact, sucess)); + })); + return false; + } + } +} diff --git a/src/MagusEngine/Actions/EscapeMenuAction.cs b/src/MagusEngine/Actions/EscapeMenuAction.cs new file mode 100644 index 00000000..bce923f3 --- /dev/null +++ b/src/MagusEngine/Actions/EscapeMenuAction.cs @@ -0,0 +1,31 @@ +using Arquimedes.Enumerators; +using MagusEngine.Actions.Interfaces; +using MagusEngine.Bus.UiBus; +using MagusEngine.Services; +using MagusEngine.Systems; +using System.Net.NetworkInformation; + +namespace MagusEngine.Actions +{ + public class EscapeMenuAction : IExecuteAction + { + private readonly MessageBusService _bus; + + public EscapeMenuAction() + { + _bus = Locator.GetService(); + } + + public bool Execute(Universe world) + { + var targetCursor = world.CurrentMap.TargetCursor; + if (targetCursor is not null) + { + targetCursor.EndTargetting(); + return true; + } + _bus.SendMessage(); + return true; + } + } +} diff --git a/src/MagusEngine/Actions/InteractAction.cs b/src/MagusEngine/Actions/InteractAction.cs new file mode 100644 index 00000000..1a74e2a6 --- /dev/null +++ b/src/MagusEngine/Actions/InteractAction.cs @@ -0,0 +1,13 @@ +using MagusEngine.Actions.Interfaces; +using MagusEngine.Systems; + +namespace MagusEngine.Actions +{ + public class InteractAction : IExecuteAction + { + public bool Execute(Universe world) + { + throw new System.NotImplementedException(); + } + } +} diff --git a/src/MagusEngine/Actions/Interfaces/IExecuteAction.cs b/src/MagusEngine/Actions/Interfaces/IExecuteAction.cs new file mode 100644 index 00000000..47da81db --- /dev/null +++ b/src/MagusEngine/Actions/Interfaces/IExecuteAction.cs @@ -0,0 +1,9 @@ +using MagusEngine.Systems; + +namespace MagusEngine.Actions.Interfaces +{ + public interface IExecuteAction + { + bool Execute(Universe world); + } +} diff --git a/src/MagusEngine/Actions/LookAction.cs b/src/MagusEngine/Actions/LookAction.cs new file mode 100644 index 00000000..b6129e3c --- /dev/null +++ b/src/MagusEngine/Actions/LookAction.cs @@ -0,0 +1,27 @@ +using Arquimedes.Enumerators; +using MagusEngine.Actions.Interfaces; +using MagusEngine.Core.Entities; +using MagusEngine.Systems; + +namespace MagusEngine.Actions +{ + public class LookAction : IExecuteAction + { + public bool Execute(Universe world) + { + var getPlayer = Find.ControlledEntity!; + var targetCursor = world!.CurrentMap!.TargetCursor ??= new Target(getPlayer.Position); + + if (targetCursor.State == TargetState.LookMode) + { + targetCursor.EndTargetting(); + } + else + { + targetCursor.StartTargetting(); + } + + return true; + } + } +} diff --git a/src/MagusEngine/Actions/MoveAction.cs b/src/MagusEngine/Actions/MoveAction.cs new file mode 100644 index 00000000..47040ea0 --- /dev/null +++ b/src/MagusEngine/Actions/MoveAction.cs @@ -0,0 +1,55 @@ +using MagusEngine.Actions.Interfaces; +using MagusEngine.Core.Entities; +using MagusEngine.Exceptions; +using MagusEngine.Systems; + +namespace MagusEngine.Actions +{ + public class MoveAction : IExecuteAction + { + private readonly Point _delta; + + public MoveAction(Point delta) + { + _delta = delta; + } + + public bool Execute(Universe world) + { + if (world.CurrentMap is null) + return false; + var actor = (Actor)world.CurrentMap.ControlledEntitiy!; + if (world.CurrentMap.ControlledEntitiy is not Player) + { + if (world.CurrentMap.CheckForIndexOutOfBounds(world.CurrentMap.ControlledEntitiy!.Position + _delta)) + return false; + + var targetCursor = world.CurrentMap.TargetCursor; + int distance = HandleNonPlayerMoveAndReturnDistance(world, _delta, targetCursor); + return world.CurrentMap.PlayerExplored[world.CurrentMap.ControlledEntitiy.Position + _delta] + && distance <= targetCursor?.MaxDistance + && actor!.MoveBy(_delta); + } + return actor!.MoveBy(_delta); + } + + private int HandleNonPlayerMoveAndReturnDistance(Universe world, Point delta, Target? targetCursor) + { + int distance = 0; + _ = world.CurrentMap ?? throw new NullValueException(nameof(world.CurrentMap)); + + if (world.CurrentMap.ControlledEntitiy == targetCursor?.Cursor) + { + _ = targetCursor ?? throw new NullValueException(nameof(targetCursor)); + + if (targetCursor.TravelPath is not null) + distance = targetCursor.TravelPath.LengthWithStart; + if (targetCursor.TravelPath is not null && targetCursor.TravelPath.LengthWithStart >= targetCursor.MaxDistance) + { + distance = world!.CurrentMap!.AStar!.ShortestPath(targetCursor.OriginCoord, world!.CurrentMap!.ControlledEntitiy!.Position + delta)!.Length; + } + } + return distance; + } + } +} diff --git a/src/MagusEngine/Actions/OpenCloseDoorAction.cs b/src/MagusEngine/Actions/OpenCloseDoorAction.cs new file mode 100644 index 00000000..3a82420b --- /dev/null +++ b/src/MagusEngine/Actions/OpenCloseDoorAction.cs @@ -0,0 +1,39 @@ +using MagusEngine.Actions.Interfaces; +using MagusEngine.Bus.MapBus; +using MagusEngine.Bus.UiBus; +using MagusEngine.Core.Entities; +using MagusEngine.Services; +using MagusEngine.Systems; +using MagusEngine.Systems.Time; + +namespace MagusEngine.Actions +{ + public class OpenCloseDoorAction : IExecuteAction + { + private readonly MessageBusService _bus; + private readonly Actor _actor; + private readonly bool _close; + + public OpenCloseDoorAction(Actor actor, bool close) + { + _bus = Locator.GetService(); + _actor = actor; + _close = close; + } + + public bool Execute(Universe world) + { + if (_close) + { + bool sucess = ActionManager.CloseDoor(world.Player); + _bus.SendMessage(new(TimeHelper.Interact, sucess)); + _bus.SendMessage(); + return sucess; + } + else + { + return false; + } + } + } +} diff --git a/src/MagusEngine/Actions/OpenInventoryAction.cs b/src/MagusEngine/Actions/OpenInventoryAction.cs new file mode 100644 index 00000000..2ed220c4 --- /dev/null +++ b/src/MagusEngine/Actions/OpenInventoryAction.cs @@ -0,0 +1,31 @@ +using System; +using MagusEngine.Actions.Interfaces; +using MagusEngine.Bus.UiBus; +using MagusEngine.Core.Entities; +using MagusEngine.Services; +using MagusEngine.Systems; + +namespace MagusEngine.Actions +{ + public class OpenInventoryAction : IExecuteAction + { + private readonly MessageBusService _bus; + private readonly Action? _action; + + public OpenInventoryAction(Action? action = null) + { + _bus = Locator.GetService(); + _action = action; + } + + public bool Execute(Universe world) + { + Actor? controlledActor = (Actor?)world?.CurrentMap?.ControlledEntitiy; + if (controlledActor is null) + return false; + + _bus.SendMessage(new(controlledActor, _action)); + return true; + } + } +} diff --git a/src/MagusEngine/Actions/OpenWaitAction.cs b/src/MagusEngine/Actions/OpenWaitAction.cs new file mode 100644 index 00000000..d8f97850 --- /dev/null +++ b/src/MagusEngine/Actions/OpenWaitAction.cs @@ -0,0 +1,24 @@ +using Arquimedes.Enumerators; +using MagusEngine.Actions.Interfaces; +using MagusEngine.Bus.UiBus; +using MagusEngine.Services; +using MagusEngine.Systems; + +namespace MagusEngine.Actions +{ + public class OpenWaitAction : IExecuteAction + { + private readonly MessageBusService _messageBus; + + public OpenWaitAction() + { + _messageBus = Locator.GetService(); + } + + public bool Execute(Universe world) + { + _messageBus.SendMessage(new(WindowTag.Wait)); + return true; + } + } +} diff --git a/src/MagusEngine/Actions/PickUpPlayerAction.cs b/src/MagusEngine/Actions/PickUpPlayerAction.cs new file mode 100644 index 00000000..f2f46134 --- /dev/null +++ b/src/MagusEngine/Actions/PickUpPlayerAction.cs @@ -0,0 +1,29 @@ +using MagusEngine.Actions.Interfaces; +using MagusEngine.Bus.MapBus; +using MagusEngine.Core.Entities; +using MagusEngine.Services; +using MagusEngine.Systems; +using MagusEngine.Systems.Time; + +namespace MagusEngine.Actions +{ + public class PickUpPlayerAction : IExecuteAction + { + private readonly Actor _actor; + private readonly MessageBusService _bus; + + public PickUpPlayerAction(Actor actor) + { + _actor = actor; + _bus = Locator.GetService(); + } + + public bool Execute(Universe world) + { + Item item = world.CurrentMap!.GetEntityAt(world.CurrentMap.ControlledEntitiy!.Position)!; + bool sucess = ActionManager.PickUp(world.Player, item!); + _bus.SendMessage(new(TimeHelper.Interact, sucess)); + return sucess; + } + } +} diff --git a/src/MagusEngine/Actions/PlanetMoveCameraAction.cs b/src/MagusEngine/Actions/PlanetMoveCameraAction.cs new file mode 100644 index 00000000..dca43f3f --- /dev/null +++ b/src/MagusEngine/Actions/PlanetMoveCameraAction.cs @@ -0,0 +1,32 @@ +using Arquimedes.Enumerators; +using MagusEngine.Actions.Interfaces; +using MagusEngine.Bus.UiBus; +using MagusEngine.Services; +using MagusEngine.Systems; + +namespace MagusEngine.Actions +{ + public class PlanetMoveCameraAction : IExecuteAction + { + private readonly Point _delta; + private readonly MessageBusService _bus; + + public PlanetMoveCameraAction(Point delta) + { + _delta = delta; + _bus = Locator.GetService(); + } + + public bool Execute(Universe world) + { + if (!CurrentMapIsPlanetView(world)) + return false; + _bus.SendMessage(new(_delta, WindowTag.Map)); + // Must return false, because there isn't any movement of the actor + return false; + } + + private static bool CurrentMapIsPlanetView(Universe world) => + world.WorldMap != null && world.WorldMap.AssocietatedMap == world.CurrentMap && world.Player == null; + } +} diff --git a/src/MagusEngine/Actions/RestAction.cs b/src/MagusEngine/Actions/RestAction.cs new file mode 100644 index 00000000..bfdaf537 --- /dev/null +++ b/src/MagusEngine/Actions/RestAction.cs @@ -0,0 +1,50 @@ +using MagusEngine.Actions.Interfaces; +using MagusEngine.Bus.UiBus; +using MagusEngine.Core.Entities; +using MagusEngine.Core.Entities.Base; +using MagusEngine.Services; +using MagusEngine.Systems; +using MagusEngine.Utils; + +namespace MagusEngine.Actions +{ + public class RestAction : IExecuteAction + { + private readonly MessageBusService _messageBus; + private readonly Actor _actor; + + public RestAction(Actor actor) + { + _messageBus = Locator.GetService(); + _actor = actor; + } + + public bool Execute(Universe world) + { + Body bodyStats = _actor.Body; + //Mind mindStats = _actor.Mind; + Soul soulStats = _actor.Soul; + + if (bodyStats.Stamina < bodyStats.MaxStamina || soulStats.CurrentMana < soulStats.MaxMana) + { + // calculate here the amount of time that it will take in turns to rest to full + double staminaDif, manaDif; + + staminaDif = MathMagi.Round((bodyStats.MaxStamina - bodyStats.Stamina) / _actor.GetStaminaRegen()); + manaDif = MathMagi.Round((soulStats.MaxMana - soulStats.CurrentMana) / _actor.GetManaRegen()); + + double totalTurnsWait = staminaDif + manaDif; + + bool sus = ActionManager.WaitForNTurns((int)totalTurnsWait, _actor); + + Locator.GetService().SendMessage(new($"You have rested for {totalTurnsWait} turns")); + + return sus; + } + + Locator.GetService().SendMessage(new("You have no need to rest")); + + return false; + } + } +} diff --git a/src/MagusEngine/Actions/SpellCastingPlayerAction.cs b/src/MagusEngine/Actions/SpellCastingPlayerAction.cs new file mode 100644 index 00000000..6418f5ad --- /dev/null +++ b/src/MagusEngine/Actions/SpellCastingPlayerAction.cs @@ -0,0 +1,33 @@ +using Arquimedes.Enumerators; +using MagusEngine.Actions.Interfaces; +using MagusEngine.Bus.UiBus; +using MagusEngine.Core.Entities; +using MagusEngine.Core.Magic; +using MagusEngine.Services; +using MagusEngine.Systems; + +namespace MagusEngine.Actions +{ + public class SpellCastingPlayerAction : IExecuteAction + { + private readonly MessageBusService _bus; + private readonly Actor _actor; + + public SpellCastingPlayerAction(Actor actor) + { + _bus = Locator.GetService(); + _actor = actor; + } + + public bool Execute(Universe world) + { + var getPlayer = (Actor)Find.ControlledEntity!; + + var targetCursor = world!.CurrentMap!.TargetCursor ??= new Target(getPlayer.Position); + var magic = getPlayer.GetComponent(); + _bus.SendMessage(new(magic.KnowSpells, getPlayer.Soul.CurrentMana, selectedSpell => targetCursor.OnSelectSpell(selectedSpell, getPlayer))); + + return true; + } + } +} diff --git a/src/MagusEngine/Actions/ThrowItemAction.cs b/src/MagusEngine/Actions/ThrowItemAction.cs new file mode 100644 index 00000000..a2e80c82 --- /dev/null +++ b/src/MagusEngine/Actions/ThrowItemAction.cs @@ -0,0 +1,41 @@ +using Arquimedes.Enumerators; +using MagusEngine; +using MagusEngine.Actions.Interfaces; +using MagusEngine.Bus.UiBus; +using MagusEngine.Core.Entities; +using MagusEngine.Services; +using MagusEngine.Systems; + +namespace MagusEngine.Actions +{ + public class ThrowItemAction : IExecuteAction + { + private Target? _targetCursor; + private readonly MessageBusService _bus; + + public ThrowItemAction() + { + _bus = Locator.GetService(); + } + + public bool Execute(Universe world) + { + Actor? controlledActor = (Actor?)world?.CurrentMap?.ControlledEntitiy; + if (controlledActor is null) + return false; + _bus.SendMessage(new(controlledActor, item => + { + _targetCursor ??= new Target(controlledActor.Position); + if (item is null) + { + _bus.SendMessage(new("No item selected!")); + return; + } + _targetCursor.OnSelectItem(item, controlledActor); + _bus.SendMessage(new(WindowTag.Inv)); + controlledActor.Inventory.Remove(item); + })); + return true; + } + } +} diff --git a/src/MagusEngine/Actions/UpDownMovementAction.cs b/src/MagusEngine/Actions/UpDownMovementAction.cs new file mode 100644 index 00000000..cbe01229 --- /dev/null +++ b/src/MagusEngine/Actions/UpDownMovementAction.cs @@ -0,0 +1,127 @@ +using MagusEngine.Actions.Interfaces; +using MagusEngine.Bus; +using MagusEngine.Bus.UiBus; +using MagusEngine.Components.TilesComponents; +using MagusEngine.Core.Entities; +using MagusEngine.Core.MapStuff; +using MagusEngine.Services; +using MagusEngine.Systems; + +namespace MagusEngine.Actions +{ + public class UpDownMovementAction : IExecuteAction + { + private readonly int _zDelta; + private readonly MessageBusService _bus; + + public UpDownMovementAction(int zDelta) + { + _zDelta = zDelta; + _bus = Locator.GetService(); + } + + public bool Execute(Universe world) + { + if (_zDelta > 0) + return UpMovement(); + else + return DownMovement(); + } + + private bool UpMovement() + { + var point = Find.CurrentMap!.ControlledEntitiy!.Position; + bool possibleChangeMap = Find.Universe.PossibleChangeMap; + Furniture? possibleStairs = Find.CurrentMap?.GetEntityAt(point); + MagiMap? currentMap = Find.CurrentMap; + + if (possibleChangeMap) + { + if (possibleStairs is not null && !Find.Universe.MapIsWorld() + && possibleStairs.MapIdConnection is not null) + { + MagiMap map = Universe.GetMapById(possibleStairs.MapIdConnection.Value)!; + _bus.SendMessage(new(map, map.GetRandomWalkableTile(), currentMap)); + + return true; + } + else if (!Find.Universe.MapIsWorld()) + { + MagiMap map = Find.Universe.WorldMap.AssocietatedMap; + Point playerLastPos = Find.Universe.WorldMap.AssocietatedMap.LastPlayerPosition; + _bus.SendMessage(new(map, playerLastPos, currentMap)); + Locator.GetService().SaveChunkInPos(Find.Universe.CurrentChunk, + Find.Universe.CurrentChunk.ToIndex(map.Width)); + Find.Universe.CurrentChunk = null!; + return true; + } + else if (Find.Universe.MapIsWorld()) + { + _bus.SendMessage(new("Can't go to the overworld since you are there!")); + return false; + } + else if (possibleStairs is null && !Find.Universe.MapIsWorld()) + { + _bus.SendMessage(new("Can't go up here!")); + return false; + } + else + { + _bus.SendMessage(new("Can't exit the map!")); + return false; + } + } + else + { + _bus.SendMessage(new("You can't change the map right now!")); + return false; + } + } + + private bool DownMovement() + { + var point = Find.CurrentMap!.ControlledEntitiy!.Position; + Furniture? possibleStairs = Find.CurrentMap?.GetEntityAt(point); + var possibleWorldTileHere = Find.CurrentMap?.GetComponentInTileAt(point); + MagiMap currentMap = Find.CurrentMap!; + if (possibleStairs?.MapIdConnection.HasValue == true) + { + MagiMap map = Universe.GetMapById(possibleStairs.MapIdConnection.Value)!; + _bus.SendMessage(new(map, map.GetRandomWalkableTile(), currentMap)); + return true; + } + else if (possibleStairs is null && possibleWorldTileHere is null) + { + _bus.SendMessage(new("There is no way to go down from here!")); + return false; + } + + if (possibleWorldTileHere?.Visited == false) + { + possibleWorldTileHere.Visited = true; + + RegionChunk chunk = Find.Universe.GenerateChunck(point); + Find.Universe.CurrentChunk = chunk; + Locator.GetService().SendMessage(new(chunk.LocalMaps[0], + chunk.LocalMaps[0].GetRandomWalkableTile(), currentMap)); + return true; + } + else if (possibleWorldTileHere?.Visited == true) + { + RegionChunk chunk = Find.Universe.GetChunckByPos(point)!; + Find.Universe.CurrentChunk = chunk; + // if entering the map again, set to update + chunk.SetMapsToUpdate(); + Locator.GetService().SendMessage(new(chunk.LocalMaps[0], + chunk.LocalMaps[0].LastPlayerPosition, currentMap)); + + return true; + } + else + { + Locator.GetService().SendMessage(new("There is nowhere to go!")); + return false; + } + } + } +} diff --git a/src/MagusEngine/Actions/WaitAction.cs b/src/MagusEngine/Actions/WaitAction.cs new file mode 100644 index 00000000..d4160679 --- /dev/null +++ b/src/MagusEngine/Actions/WaitAction.cs @@ -0,0 +1,26 @@ +using MagusEngine.Actions.Interfaces; +using MagusEngine.Bus.MapBus; +using MagusEngine.Services; +using MagusEngine.Systems; + +namespace MagusEngine.Actions +{ + public class WaitAction : IExecuteAction + { + private readonly int _time; + private readonly MessageBusService _bus; + + public WaitAction(int time) + { + _bus = Locator.GetService(); + _time = time; + } + + public bool Execute(Universe world) + { + Locator.GetService().SendMessage(new(_time, true)); + + return true; + } + } +} diff --git a/src/MagusEngine/Bus/StartGameMessage.cs b/src/MagusEngine/Bus/StartGameMessage.cs index 6f02a1ad..7bb25825 100644 --- a/src/MagusEngine/Bus/StartGameMessage.cs +++ b/src/MagusEngine/Bus/StartGameMessage.cs @@ -9,7 +9,7 @@ public class StartGameMessage public Universe? Universe { get; set; } public bool TestGame { get; set; } - public StartGameMessage(Player player, Universe universe = null) + public StartGameMessage(Player player, Universe? universe = null) { Player = player; Universe = universe; diff --git a/src/MagusEngine/Bus/UiBus/CloseWindowMessage.cs b/src/MagusEngine/Bus/UiBus/CloseWindowMessage.cs new file mode 100644 index 00000000..3ed11858 --- /dev/null +++ b/src/MagusEngine/Bus/UiBus/CloseWindowMessage.cs @@ -0,0 +1,14 @@ +using Arquimedes.Enumerators; + +namespace MagusEngine.Bus.UiBus +{ + public class CloseWindowMessage + { + public WindowTag Tag { get; set; } + + public CloseWindowMessage(WindowTag tag) + { + Tag = tag; + } + } +} diff --git a/src/MagusEngine/Bus/UiBus/InventoryActionBus.cs b/src/MagusEngine/Bus/UiBus/InventoryActionBus.cs new file mode 100644 index 00000000..ee7d5782 --- /dev/null +++ b/src/MagusEngine/Bus/UiBus/InventoryActionBus.cs @@ -0,0 +1,17 @@ +using System; +using MagusEngine.Core.Entities; + +namespace MagusEngine.Bus.UiBus +{ + public class InventoryActionBus + { + public Actor ActorInventory { get; } + public Action? Action { get; } + + public InventoryActionBus(Actor actorInventory, Action? action) + { + ActorInventory = actorInventory; + Action = action; + } + } +} diff --git a/src/MagusEngine/Bus/UiBus/OpenSpellCastingWindowMessage.cs b/src/MagusEngine/Bus/UiBus/OpenSpellCastingWindowMessage.cs new file mode 100644 index 00000000..60d14dc1 --- /dev/null +++ b/src/MagusEngine/Bus/UiBus/OpenSpellCastingWindowMessage.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using MagusEngine.Core.Magic; + +namespace MagusEngine.Bus.UiBus +{ + public class OpenSpellCastingWindowMessage + { + public List Spells { get; set; } = null!; + public double CurrentMana { get; set; } + public Action? OnCast { get; set; } + + public OpenSpellCastingWindowMessage(List spells, double currentMana, Action? onCast) + { + Spells = spells; + CurrentMana = currentMana; + OnCast = onCast; + } + } +} diff --git a/src/MagusEngine/Bus/UiBus/OpenWindowEvent.cs b/src/MagusEngine/Bus/UiBus/OpenWindowEvent.cs new file mode 100644 index 00000000..f60e26cd --- /dev/null +++ b/src/MagusEngine/Bus/UiBus/OpenWindowEvent.cs @@ -0,0 +1,14 @@ +using Arquimedes.Enumerators; + +namespace MagusEngine.Bus.UiBus +{ + public class OpenWindowEvent + { + public WindowTag Window { get; } + + public OpenWindowEvent(WindowTag window) + { + Window = window; + } + } +} diff --git a/src/MagusEngine/Bus/UiBus/ScrollConsoleMessage.cs b/src/MagusEngine/Bus/UiBus/ScrollConsoleMessage.cs new file mode 100644 index 00000000..10b5084b --- /dev/null +++ b/src/MagusEngine/Bus/UiBus/ScrollConsoleMessage.cs @@ -0,0 +1,16 @@ +using Arquimedes.Enumerators; + +namespace MagusEngine.Bus.UiBus +{ + public class ScrollConsoleMessage + { + public Point Delta { get; } + public WindowTag Tag { get; } + + public ScrollConsoleMessage(Point delta, WindowTag tag) + { + Delta = delta; + Tag = tag; + } + } +} diff --git a/src/MagusEngine/Components/EntityComponents/Ai/BasicAi.cs b/src/MagusEngine/Components/EntityComponents/Ai/BasicAi.cs index dfdefdf4..d17b6a80 100644 --- a/src/MagusEngine/Components/EntityComponents/Ai/BasicAi.cs +++ b/src/MagusEngine/Components/EntityComponents/Ai/BasicAi.cs @@ -23,7 +23,7 @@ public virtual (bool sucess, long ticks) RunAi(MagiMap? map) if (rng) { Locator.GetService().SendMessage(new($"The {_entity.Name} waits doing nothing...")); - return (true, TimeHelper.Wait); + return (true, TimeHelper.OneSecond); } else { diff --git a/src/MagusEngine/Components/EntityComponents/Ai/MoveAndAttackAI.cs b/src/MagusEngine/Components/EntityComponents/Ai/MoveAndAttackAI.cs index 28eaa498..69fd9b39 100644 --- a/src/MagusEngine/Components/EntityComponents/Ai/MoveAndAttackAI.cs +++ b/src/MagusEngine/Components/EntityComponents/Ai/MoveAndAttackAI.cs @@ -38,7 +38,7 @@ public MoveAndAttackAI(int perception) } else { - return (true, TimeHelper.Wait); + return (true, TimeHelper.OneSecond); } } diff --git a/src/MagusEngine/Core/MapStuff/MagiMap.cs b/src/MagusEngine/Core/MapStuff/MagiMap.cs index 52e308c2..38c46545 100644 --- a/src/MagusEngine/Core/MapStuff/MagiMap.cs +++ b/src/MagusEngine/Core/MapStuff/MagiMap.cs @@ -82,6 +82,7 @@ public MagiEntity? ControlledEntitiy public List? Rooms { get; set; } public EntityManager EntityRender { get; private set; } = []; + public Target? TargetCursor { get; set; } #endregion Properties diff --git a/src/MagusEngine/MagusEngine.csproj b/src/MagusEngine/MagusEngine.csproj index 71b988ba..df3a4302 100644 --- a/src/MagusEngine/MagusEngine.csproj +++ b/src/MagusEngine/MagusEngine.csproj @@ -1,14 +1,13 @@ - net9.0 + net10.0 enable True - diff --git a/src/MagusEngine/Services/Factory/AnimationFactory.cs b/src/MagusEngine/Services/Factory/AnimationFactory.cs index 0e43542c..bf45afc8 100644 --- a/src/MagusEngine/Services/Factory/AnimationFactory.cs +++ b/src/MagusEngine/Services/Factory/AnimationFactory.cs @@ -6,7 +6,7 @@ namespace MagusEngine.Services.Factory { - public sealed class AnimationFactory : GenericFactory + public sealed class AnimationFactory : GenericJsonFactory { public AnimationFactory() { diff --git a/src/MagusEngine/Services/Factory/Base/GenericFactory.cs b/src/MagusEngine/Services/Factory/Base/GenericJsonFactory.cs similarity index 74% rename from src/MagusEngine/Services/Factory/Base/GenericFactory.cs rename to src/MagusEngine/Services/Factory/Base/GenericJsonFactory.cs index 3874833f..ddd6413f 100644 --- a/src/MagusEngine/Services/Factory/Base/GenericFactory.cs +++ b/src/MagusEngine/Services/Factory/Base/GenericJsonFactory.cs @@ -5,7 +5,7 @@ namespace MagusEngine.Services.Factory.Base { - public abstract class GenericFactory + public abstract class GenericJsonFactory { protected Dictionary> Factories { get; } = []; @@ -20,6 +20,18 @@ public virtual bool Register(string key, Func factory) return Factories.TryAdd(key, factory); } + public virtual bool Register(Enum key, Func factory) + { + var str = key.ToString(); + if (string.IsNullOrWhiteSpace(str)) + { + throw new ArgumentException("Key cannot be null or empty.", nameof(key)); + } + ArgumentNullException.ThrowIfNull(factory); + + return Factories.TryAdd(str, factory); + } + public virtual T GetValueFromKey(string key, JToken token) { return Factories.TryGetValue(key, out var factory) diff --git a/src/MagusEngine/Services/Factory/SpellEffectFactory.cs b/src/MagusEngine/Services/Factory/SpellEffectFactory.cs index 0d23a5a2..27996460 100644 --- a/src/MagusEngine/Services/Factory/SpellEffectFactory.cs +++ b/src/MagusEngine/Services/Factory/SpellEffectFactory.cs @@ -7,7 +7,7 @@ namespace MagusEngine.Services.Factory { - public sealed class SpellEffectFactory : GenericFactory + public sealed class SpellEffectFactory : GenericJsonFactory { public SpellEffectFactory() { diff --git a/src/MagusEngine/Services/MessageBusService.cs b/src/MagusEngine/Services/MessageBusService.cs index bf8a62d7..778a1890 100644 --- a/src/MagusEngine/Services/MessageBusService.cs +++ b/src/MagusEngine/Services/MessageBusService.cs @@ -28,8 +28,8 @@ public void SendMessage(T obj) where T : notnull [DebuggerStepThrough] public void SendMessage() where T : notnull, new() { - var instance = Activator.CreateInstance(typeof(T)); - _messageBus?.Send((T)instance!); + var instance = Activator.CreateInstance(); + _messageBus?.Send(instance); } /// diff --git a/src/MagusEngine/Systems/Find.cs b/src/MagusEngine/Systems/Find.cs index 78a302e9..dbeef778 100644 --- a/src/MagusEngine/Systems/Find.cs +++ b/src/MagusEngine/Systems/Find.cs @@ -2,6 +2,7 @@ using Arquimedes.Enumerators; using MagusEngine.Components.TilesComponents; using MagusEngine.Core.Civ; +using MagusEngine.Core.Entities; using MagusEngine.Core.Entities.Base; using MagusEngine.Core.MapStuff; using MagusEngine.Core.WorldStuff.History; @@ -33,7 +34,7 @@ public static void PopulateValues(AccumulatedHistory h, WorldTile[,] tiles) { history = h; Tiles = tiles; - Rules ??= new(DataManager.ListOfRules.GetEnumerableCollection()); + Rules ??= [.. DataManager.ListOfRules.GetEnumerableCollection()]; } public static Site? GetFigureStayingSiteIfAny(HistoricalFigure hf) diff --git a/src/MagusEngine/Systems/Time/TimeHelper.cs b/src/MagusEngine/Systems/Time/TimeHelper.cs index ab030ec3..6ed3d9b2 100644 --- a/src/MagusEngine/Systems/Time/TimeHelper.cs +++ b/src/MagusEngine/Systems/Time/TimeHelper.cs @@ -1,4 +1,5 @@ -using MagusEngine.Core.Entities; +using System; +using MagusEngine.Core.Entities; using MagusEngine.Core.Entities.Base; using MagusEngine.Core.Magic; using MagusEngine.Core.MapStuff; @@ -7,10 +8,10 @@ namespace MagusEngine.Systems.Time { public static class TimeHelper { - public const int Wait = 100; + public const int OneMoment = 10; + public const int OneSecond = 100; public const int Interact = 50; - public const int Wear = 200; - public const int MagicalThings = 650; + public const int MagicalThingsTimeModifer = 650; public const int AiFailed = -1; public static long GetWalkTime(Actor actor, Tile tileToMove) @@ -39,17 +40,33 @@ public static long GetWorldWalkTime(Actor actor, Tile tile) public static long GetAttackTime(Actor actor, Attack attack) { - return (long)actor.GetAttackVelocity(attack) / ((int)attack.RecoverVelocity + 1); + // Improved attack time calculation with realistic physics + double baseTime = attack.PrepareVelocity + attack.RecoverVelocity; + double actorSpeed = actor.GetActorSpeed(); + double skillBonus = Math.Max(0.5, 1.0 - (actor.GetRelevantAttackAbility(actor.WieldedItem()) * 0.01)); + + return (long)(baseTime * skillBonus / Math.Max(actorSpeed, 0.1)); + } + + public static long GetAttackTimeWithWeapon(Actor actor, Attack attack, Item weapon) + { + double baseTime = attack.PrepareVelocity + attack.RecoverVelocity; + double weaponWeight = weapon?.Mass ?? 1.0; + double actorSpeed = actor.GetActorSpeed(); + double skillBonus = Math.Max(0.5, 1.0 - (actor.GetRelevantAttackAbility(weapon) * 0.01)); + double strengthFactor = Math.Max(0.5, 1.0 + (actor.GetStrenght() - weaponWeight) * 0.01); + + return (long)(baseTime * weaponWeight * skillBonus * strengthFactor / Math.Max(actorSpeed, 0.1)); } public static long GetCastingTime(Actor actor, Spell spellCasted) { - return (long)(MagicalThings * (spellCasted.SpellLevel + (spellCasted.MagicCost * 5)) / actor.GetActorBaseCastingSpeed(spellCasted.ShapingAbility)); + return (long)(MagicalThingsTimeModifer * (spellCasted.SpellLevel + (spellCasted.MagicCost * 5)) / actor.GetActorBaseCastingSpeed(spellCasted.ShapingAbility)); } - public static long GetShootingTime(Player getPlayer, double mass) + public static long GetShootingTime(Actor getPlayer, double mass) { - return (long)(Wait + (mass * 10 / (getPlayer.GetActorSpeed()))); + return (long)(OneSecond + (mass * 10 / getPlayer.GetActorSpeed())); } } } diff --git a/src/MagusEngine/Systems/Universe.cs b/src/MagusEngine/Systems/Universe.cs index fa64a72b..df6757d6 100644 --- a/src/MagusEngine/Systems/Universe.cs +++ b/src/MagusEngine/Systems/Universe.cs @@ -398,7 +398,7 @@ private void ProcessAiTurn(uint entityId) if (sucesses >= 0 && totalTicks <= 0) { - totalTicks = TimeHelper.Wait; + totalTicks = TimeHelper.OneSecond; MagiLog.Log($"The {entity.Name} with id {entityId} has reported no success on AI"); }