├── Resources ├── Icon1.ico └── Icon2.ico ├── Settings ├── Shape.cs ├── MapPosition.cs ├── PointOfInterestRendering.cs ├── Utils.cs └── Settings.cs ├── Structs ├── RoomEx.cs ├── UiSettings.cs ├── Level.cs ├── Act.cs ├── UnitHashTable.cs ├── ActMisc.cs ├── Path.cs ├── Room.cs ├── Monster.cs └── UnitAny.cs ├── MapAssist.sln ├── Types ├── PointOfInterest.cs ├── Difficulty.cs ├── Offsets.cs ├── AreaData.cs ├── GameData.cs ├── RawAreaData.cs ├── Area.cs ├── Stats.cs └── GameObject.cs ├── .github └── workflows │ ├── msbuild.yml │ ├── release.yml │ └── nightly.yml ├── Helpers ├── Extensions.cs ├── WindowsExternal.cs ├── MapApi.cs ├── PointOfInterestHandler.cs ├── ImageUtils.cs ├── Compositor.cs └── GameMemory.cs ├── README.md ├── Program.cs ├── Properties └── AssemblyInfo.cs ├── Overlay.Designer.cs ├── .gitignore ├── App.config ├── MapAssist.csproj ├── .editorconfig └── Overlay.cs /Resources/Icon1.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RushTheOne/MapAssist/HEAD/Resources/Icon1.ico -------------------------------------------------------------------------------- /Resources/Icon2.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RushTheOne/MapAssist/HEAD/Resources/Icon2.ico -------------------------------------------------------------------------------- /Settings/Shape.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | namespace MapAssist.Settings 21 | { 22 | public enum Shape 23 | { 24 | None, 25 | Rectangle, 26 | Ellipse 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Settings/MapPosition.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | namespace MapAssist.Settings 21 | { 22 | public enum MapPosition 23 | { 24 | TopLeft, 25 | TopRight, 26 | Center 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Structs/RoomEx.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Runtime.InteropServices; 21 | 22 | namespace MapAssist.Structs 23 | { 24 | [StructLayout(LayoutKind.Explicit)] 25 | unsafe public struct RoomEx 26 | { 27 | [FieldOffset(0x90)] public Level* pLevel; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Structs/UiSettings.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Runtime.InteropServices; 21 | 22 | namespace MapAssist.Structs 23 | { 24 | [StructLayout(LayoutKind.Explicit)] 25 | unsafe public struct UiSettings 26 | { 27 | [FieldOffset(0x00)] public byte MapShown; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Structs/Level.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Runtime.InteropServices; 21 | using MapAssist.Types; 22 | 23 | namespace MapAssist.Structs 24 | { 25 | [StructLayout(LayoutKind.Explicit)] 26 | unsafe public struct Level 27 | { 28 | [FieldOffset(0x1F8)] public Area LevelId; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /MapAssist.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31727.386 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapAssist", "MapAssist.csproj", "{FB3AC437-B7BB-42FF-A2A2-F10551F95F6C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {FB3AC437-B7BB-42FF-A2A2-F10551F95F6C}.Debug|x64.ActiveCfg = Debug|x64 15 | {FB3AC437-B7BB-42FF-A2A2-F10551F95F6C}.Debug|x64.Build.0 = Debug|x64 16 | {FB3AC437-B7BB-42FF-A2A2-F10551F95F6C}.Release|x64.ActiveCfg = Release|x64 17 | {FB3AC437-B7BB-42FF-A2A2-F10551F95F6C}.Release|x64.Build.0 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {F3FD903D-7D06-41F3-BEE3-6AEF2D88C726} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Types/PointOfInterest.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Drawing; 21 | using MapAssist.Settings; 22 | 23 | namespace MapAssist.Types 24 | { 25 | public class PointOfInterest 26 | { 27 | public string Label; 28 | public Point Position; 29 | public PointOfInterestRendering RenderingSettings; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Structs/Act.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Runtime.InteropServices; 21 | 22 | namespace MapAssist.Structs 23 | { 24 | [StructLayout(LayoutKind.Explicit)] 25 | unsafe public struct Act 26 | { 27 | [FieldOffset(0x14)] public uint MapSeed; 28 | [FieldOffset(0x20)] public uint ActId; 29 | [FieldOffset(0x70)] public ActMisc* ActMisc; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.github/workflows/msbuild.yml: -------------------------------------------------------------------------------- 1 | name: MSBuild 2 | 3 | on: [push] 4 | 5 | env: 6 | # Path to the solution file relative to the root of the project. 7 | SOLUTION_FILE_PATH: . 8 | 9 | # Configuration type to build. 10 | # You can convert this to a build matrix if you need coverage of multiple configuration types. 11 | # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 12 | BUILD_CONFIGURATION: Release 13 | 14 | jobs: 15 | build: 16 | runs-on: windows-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - name: Add MSBuild to PATH 22 | uses: microsoft/setup-msbuild@v1.0.2 23 | 24 | - name: Restore NuGet packages 25 | working-directory: ${{env.GITHUB_WORKSPACE}} 26 | run: nuget restore ${{env.SOLUTION_FILE_PATH}} 27 | 28 | - name: Build 29 | working-directory: ${{env.GITHUB_WORKSPACE}} 30 | # Add additional options to the MSBuild command line here (like platform or verbosity level). 31 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference 32 | run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}} 33 | -------------------------------------------------------------------------------- /Structs/UnitHashTable.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System; 21 | using System.Runtime.InteropServices; 22 | 23 | namespace MapAssist.Structs 24 | { 25 | [StructLayout(LayoutKind.Explicit)] 26 | unsafe public struct UnitHashTable 27 | { 28 | [FieldOffset(0x00)] 29 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] 30 | public IntPtr[] UnitTable; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Structs/ActMisc.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Runtime.InteropServices; 21 | using MapAssist.Types; 22 | 23 | namespace MapAssist.Structs 24 | { 25 | [StructLayout(LayoutKind.Explicit)] 26 | unsafe public struct ActMisc 27 | { 28 | [FieldOffset(0x830)] public Difficulty GameDifficulty; 29 | [FieldOffset(0x858)] public Act* pAct; 30 | [FieldOffset(0x868)] public Level* pLevelFirst; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Structs/Path.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Runtime.InteropServices; 21 | 22 | namespace MapAssist.Structs 23 | { 24 | [StructLayout(LayoutKind.Explicit)] 25 | unsafe public struct Path 26 | { 27 | [FieldOffset(0x02)] public ushort DynamicX; 28 | [FieldOffset(0x06)] public ushort DynamicY; 29 | [FieldOffset(0x10)] public ushort StaticX; 30 | [FieldOffset(0x14)] public ushort StaticY; 31 | [FieldOffset(0x20)] public Room* pRoom; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Helpers/Extensions.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo, OneXDeveloper 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Drawing; 21 | using MapAssist.Types; 22 | 23 | namespace MapAssist.Helpers 24 | { 25 | public static class Extensions 26 | { 27 | public static bool IsWaypoint(this GameObject obj) => obj.ToString().Contains("Waypoint"); 28 | 29 | public static Point OffsetFrom(this Point point, Point offset) 30 | { 31 | return new Point(point.X - offset.X, point.Y - offset.Y); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Types/Difficulty.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | namespace MapAssist.Types 21 | { 22 | public enum Difficulty : ushort 23 | { 24 | None = 99, 25 | Normal = 0, 26 | Nightmare = 1, 27 | Hell = 2 28 | } 29 | 30 | public static class DifficultyExtension 31 | { 32 | public static bool IsValid(this Difficulty difficulty) 33 | { 34 | return (ushort)difficulty >= 0 && (ushort)difficulty <= 2; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Types/Offsets.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | using System; 20 | using System.Configuration; 21 | 22 | namespace MapAssist.Types 23 | { 24 | public static class Offsets 25 | { 26 | public static int UnitHashTable = Convert.ToInt32(ConfigurationManager.AppSettings["UnitHashTable"], 16); 27 | public static int UiSettings = Convert.ToInt32(ConfigurationManager.AppSettings["UiSettings"], 16); 28 | public static int ExpansionCheck = Convert.ToInt32(ConfigurationManager.AppSettings["ExpansionCheck"], 16); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Structs/Room.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Runtime.InteropServices; 21 | 22 | namespace MapAssist.Structs 23 | { 24 | [StructLayout(LayoutKind.Explicit)] 25 | unsafe public struct Room 26 | { 27 | [FieldOffset(0x00)] public Room** pRoomsNear; 28 | [FieldOffset(0x18)] public RoomEx* pRoomEx; 29 | [FieldOffset(0x40)] public uint numRoomsNear; 30 | [FieldOffset(0x48)] public Act* pAct; 31 | [FieldOffset(0xA8)] public UnitAny* pUnitFirst; 32 | [FieldOffset(0xB0)] public Room* pRoomNext; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Discord server down? Try this new invite link 2 | 3 | https://discord.gg/2ehpxyS3YZ 4 | 5 | # MapAssist 6 | 7 | 8 | THE 'MapAssist' TOOL AND CONTENTS THEREIN WERE INTENDED FOR INFORMATIONAL AND LEARNING PURPOSES ONLY. 9 | 10 | Join the discussion: https://discord.gg/5b2B7QrVqa 11 | 12 | Feel free to contribute a pull request with new features or fixes, the code is under GPL so make sure to please follow the license. 13 | 14 | The software is free and open source licensed under the GPLv3. You may download a copy of the source code and follow the instructions to build the software for yourself. In certain instances there may be direct links to precompiled versions of the software, you are free to use these as well. The best place to start looking is inside of the repository. 15 | 16 | Use at your own risk! The MapAssist team makes no expression of warranty or claim about the safety in regards to the usage of this program. We have done our best to provide an open project for learning and educational purposes only. The contents of the official source code are known to not contain any malicious or disingenuous code. If you have additional information in regards to the safety of this program please do not hesitate to raise a concern. 17 | 18 | All software projects are subject to their own licensing, and copyrights. All other product names and any registered and unregistered trademarks mentioned are used for identification purposes only and remain the exclusive property of their respective owners. 19 | -------------------------------------------------------------------------------- /Types/AreaData.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Collections.Generic; 21 | using System.Drawing; 22 | 23 | namespace MapAssist.Types 24 | { 25 | public class AdjacentLevel 26 | { 27 | public Area Area; 28 | public Point[] Exits; 29 | public Point Origin; 30 | public int Width; 31 | public int Height; 32 | } 33 | 34 | public class AreaData 35 | { 36 | public Area Area; 37 | public Point Origin; 38 | public Dictionary AdjacentLevels; 39 | public int[][] CollisionGrid; 40 | public Dictionary NPCs; 41 | public Dictionary Objects; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System; 21 | using System.Windows.Forms; 22 | using Gma.System.MouseKeyHook; 23 | 24 | namespace MapAssist 25 | { 26 | static class Program 27 | { 28 | /// 29 | /// The main entry point for the application. 30 | /// 31 | [STAThread] 32 | static void Main() 33 | { 34 | using (IKeyboardMouseEvents globalHook = Hook.GlobalEvents()) 35 | { 36 | Application.EnableVisualStyles(); 37 | Application.SetCompatibleTextRenderingDefault(false); 38 | Application.Run(new Overlay(globalHook)); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | workflow_dispatch: 8 | 9 | env: 10 | # Path to the solution file relative to the root of the project. 11 | SOLUTION_FILE_PATH: . 12 | 13 | # Configuration type to build. 14 | # You can convert this to a build matrix if you need coverage of multiple configuration types. 15 | # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 16 | BUILD_CONFIGURATION: Release 17 | 18 | jobs: 19 | tagged-release: 20 | name: "Tagged Release" 21 | runs-on: windows-latest 22 | 23 | steps: 24 | - uses: actions/checkout@v2 25 | 26 | - name: Add MSBuild to PATH 27 | uses: microsoft/setup-msbuild@v1.0.2 28 | 29 | - name: Restore NuGet packages 30 | working-directory: ${{env.GITHUB_WORKSPACE}} 31 | run: nuget restore ${{env.SOLUTION_FILE_PATH}} 32 | 33 | - name: Build 34 | working-directory: ${{env.GITHUB_WORKSPACE}} 35 | # Add additional options to the MSBuild command line here (like platform or verbosity level). 36 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference 37 | run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}} /p:DebugSymbols=false 38 | 39 | - name: Zip release 40 | uses: papeloto/action-zip@v1 41 | with: 42 | files: bin/x64/Release/ LICENSE README.md 43 | recursive: true 44 | dest: MapAssist.zip 45 | 46 | - name: Publish release 47 | uses: "marvinpinto/action-automatic-releases@latest" 48 | with: 49 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 50 | automatic_release_tag: "latest" 51 | prerelease: false 52 | files: | 53 | LICENSE 54 | README.md 55 | MapAssist.zip 56 | -------------------------------------------------------------------------------- /Types/GameData.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System; 21 | using System.Drawing; 22 | 23 | namespace MapAssist.Types 24 | { 25 | public class GameData 26 | { 27 | public Point PlayerPosition; 28 | public uint MapSeed; 29 | public Difficulty Difficulty; 30 | public Area Area; 31 | public bool MapShown; 32 | public IntPtr MainWindowHandle; 33 | public string PlayerName; 34 | 35 | public bool HasGameChanged(GameData other) 36 | { 37 | if (other == null) return true; 38 | if (MapSeed != other.MapSeed) return true; 39 | if (Difficulty != other.Difficulty) return true; 40 | if (PlayerName != other.PlayerName) return true; 41 | return false; 42 | } 43 | 44 | public bool HasMapChanged(GameData other) 45 | { 46 | return HasGameChanged(other) || Area != other.Area; 47 | } 48 | 49 | public override string ToString() 50 | { 51 | return 52 | $"{nameof(PlayerPosition)}: {PlayerPosition}, {nameof(MapSeed)}: {MapSeed}, {nameof(Difficulty)}: {Difficulty}, {nameof(Area)}: {Area}, {nameof(MapShown)}: {MapShown}"; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Structs/Monster.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Runtime.InteropServices; 21 | using System.Drawing; 22 | using System.Collections.Generic; 23 | using MapAssist.Types; 24 | using System; 25 | 26 | namespace MapAssist.Structs 27 | { 28 | public struct Monster 29 | { 30 | public Point Position; 31 | public uint UniqueFlag; 32 | public List Immunities; 33 | } 34 | [StructLayout(LayoutKind.Explicit)] 35 | public struct MonStats 36 | { 37 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 38 | [FieldOffset(0x00)] public byte[] Name; 39 | } 40 | 41 | [StructLayout(LayoutKind.Explicit)] 42 | public struct MonsterData 43 | { 44 | [FieldOffset(0x0)] public IntPtr pMonStats; 45 | [FieldOffset(0x8)] public ulong ShrineType; 46 | [FieldOffset(0x1A)] public MonsterTypeFlags MonsterType; 47 | } 48 | [Flags] 49 | public enum MonsterTypeFlags : byte 50 | { 51 | None = 0, 52 | Other = 1, 53 | SuperUnique = 1 << 1, 54 | Champion = 1 << 2, 55 | Unique = 1 << 3, 56 | Minion = 1 << 4, 57 | Possessed = 1 << 5, 58 | Ghostly = 1 << 6, 59 | Multishot = 1 << 7, 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Settings/PointOfInterestRendering.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Drawing; 21 | 22 | namespace MapAssist.Settings 23 | { 24 | public class PointOfInterestRendering 25 | { 26 | public Color IconColor; 27 | public Shape IconShape; 28 | public int IconSize; 29 | 30 | public Color LineColor; 31 | public float LineThickness; 32 | 33 | public int ArrowHeadSize; 34 | 35 | public Color LabelColor; 36 | public string LabelFont; 37 | public int LabelFontSize; 38 | 39 | public bool CanDrawIcon() 40 | { 41 | return IconShape != Shape.None && IconSize > 0 && IconColor != Color.Transparent; 42 | } 43 | 44 | public bool CanDrawLine() 45 | { 46 | return LineColor != Color.Transparent && LineThickness > 0; 47 | } 48 | 49 | public bool CanDrawArrowHead() 50 | { 51 | return CanDrawLine() && ArrowHeadSize > 0; 52 | } 53 | 54 | public bool CanDrawLabel() 55 | { 56 | return LabelColor != Color.Transparent && !string.IsNullOrWhiteSpace(LabelFont) && 57 | LabelFontSize > 0; 58 | } 59 | } 60 | public class MobRendering 61 | { 62 | public Color NormalColor; 63 | public Color UniqueColor; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | #if DEBUG 21 | using System.Reflection; 22 | using System.Runtime.InteropServices; 23 | 24 | // General Information about an assembly is controlled through the following 25 | // set of attributes. Change these attribute values to modify the information 26 | // associated with an assembly. 27 | [assembly: AssemblyTitle("")] 28 | [assembly: AssemblyDescription("")] 29 | [assembly: AssemblyConfiguration("")] 30 | [assembly: AssemblyCompany("")] 31 | [assembly: AssemblyProduct("MapAssist")] 32 | [assembly: AssemblyCopyright("Copyright © 2021")] 33 | [assembly: AssemblyTrademark("")] 34 | [assembly: AssemblyCulture("")] 35 | 36 | // Setting ComVisible to false makes the types in this assembly not visible 37 | // to COM components. If you need to access a type in this assembly from 38 | // COM, set the ComVisible attribute to true on that type. 39 | [assembly: ComVisible(false)] 40 | 41 | // The following GUID is for the ID of the typelib if this project is exposed to COM 42 | [assembly: Guid("fb3ac437-b7bb-42ff-a2a2-f10551f95f6c")] 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.2.0")] 55 | [assembly: AssemblyFileVersion("1.2.0")] 56 | #endif 57 | -------------------------------------------------------------------------------- /Overlay.Designer.cs: -------------------------------------------------------------------------------- 1 | 2 | using System; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Windows.Forms; 6 | 7 | namespace MapAssist 8 | { 9 | partial class Overlay 10 | { 11 | /// 12 | /// Required designer variable. 13 | /// 14 | private IContainer components = null; 15 | 16 | /// 17 | /// Clean up any resources being used. 18 | /// 19 | /// true if managed resources should be disposed; otherwise, false. 20 | protected override void Dispose(bool disposing) 21 | { 22 | if (disposing && (components != null)) 23 | { 24 | components.Dispose(); 25 | } 26 | base.Dispose(disposing); 27 | } 28 | 29 | #region Windows Form Designer generated code 30 | 31 | /// 32 | /// Required method for Designer support - do not modify 33 | /// the contents of this method with the code editor. 34 | /// 35 | private void InitializeComponent() 36 | { 37 | ComponentResourceManager resources = new ComponentResourceManager(typeof(Overlay)); 38 | mapOverlay = new PictureBox(); 39 | ((ISupportInitialize)(mapOverlay)).BeginInit(); 40 | this.SuspendLayout(); 41 | // 42 | // mapOverlay 43 | // 44 | mapOverlay.BackColor = Color.Transparent; 45 | mapOverlay.Location = new Point(12, 3); 46 | mapOverlay.Name = "mapOverlay"; 47 | mapOverlay.Size = new Size(0, 0); 48 | mapOverlay.TabIndex = 0; 49 | mapOverlay.TabStop = false; 50 | mapOverlay.Paint += new PaintEventHandler(MapOverlay_Paint); 51 | 52 | // 53 | // frmOverlay 54 | // 55 | AutoScaleDimensions = new SizeF(6F, 13F); 56 | AutoScaleMode = AutoScaleMode.Font; 57 | ClientSize = new Size(1767, 996); 58 | Controls.Add(mapOverlay); 59 | FormBorderStyle = FormBorderStyle.None; 60 | Icon = (Icon)(resources.GetObject("$this.Icon")); 61 | Name = "Overlay"; 62 | TransparencyKey = Color.Black; 63 | BackColor = Color.Black; 64 | WindowState = FormWindowState.Maximized; 65 | Load += new EventHandler(Overlay_Load); 66 | FormClosing += new FormClosingEventHandler(Overlay_FormClosing); 67 | ((ISupportInitialize)(mapOverlay)).EndInit(); 68 | ResumeLayout(false); 69 | } 70 | 71 | #endregion 72 | 73 | private PictureBox mapOverlay; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Structs/UnitAny.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System; 21 | using System.Runtime.InteropServices; 22 | using MapAssist.Types; 23 | 24 | namespace MapAssist.Structs 25 | { 26 | [StructLayout(LayoutKind.Explicit)] 27 | unsafe public struct UnitAny 28 | { 29 | [FieldOffset(0x00)] public uint UnitType; 30 | [FieldOffset(0x04)] public uint TxtFileNo; 31 | [FieldOffset(0x08)] public uint UnitId; 32 | [FieldOffset(0x0C)] public uint Mode; 33 | [FieldOffset(0x10)] public IntPtr UnitData; 34 | [FieldOffset(0x10)] public IntPtr IsPlayer; 35 | [FieldOffset(0x20)] public Act* pAct; 36 | [FieldOffset(0x38)] public Path* pPath; 37 | [FieldOffset(0x88)] public IntPtr StatsListEx; 38 | [FieldOffset(0x90)] public IntPtr Inventory; 39 | [FieldOffset(0xB8)] public uint OwnerType; // ? 40 | [FieldOffset(0xC4)] public ushort X; 41 | [FieldOffset(0xC6)] public ushort Y; 42 | [FieldOffset(0x150)] public UnitAny* pListNext; 43 | [FieldOffset(0x158)] public UnitAny* pRoomNext; 44 | 45 | public override bool Equals(object obj) => obj is UnitAny other && Equals(other); 46 | 47 | public bool Equals(UnitAny unit) => UnitId == unit.UnitId; 48 | 49 | public override int GetHashCode() => UnitId.GetHashCode(); 50 | 51 | public static bool operator ==(UnitAny unit1, UnitAny unit2) => unit1.Equals(unit2); 52 | 53 | public static bool operator !=(UnitAny unit1, UnitAny unit2) => !(unit1 == unit2); 54 | } 55 | [StructLayout(LayoutKind.Explicit)] 56 | public readonly struct StatValue 57 | { 58 | [FieldOffset(0x0)] public readonly ushort Layer; 59 | [FieldOffset(0x2)] public readonly Stat Stat; 60 | [FieldOffset(0x4)] public readonly int Value; 61 | } 62 | 63 | [StructLayout(LayoutKind.Explicit)] 64 | public readonly struct StatArrayStruct 65 | { 66 | [FieldOffset(0x0)] public readonly IntPtr FirstStatPtr; 67 | [FieldOffset(0x8)] public readonly ulong Size; 68 | [FieldOffset(0x10)] public readonly ulong Capacity; 69 | } 70 | 71 | [StructLayout(LayoutKind.Explicit)] 72 | public readonly struct StatListStruct 73 | { 74 | [FieldOffset(0x8)] public readonly uint OwnerType; 75 | [FieldOffset(0xC)] public readonly uint OwnerId; 76 | [FieldOffset(0x1C)] public readonly uint Flags; 77 | [FieldOffset(0x30)] public readonly StatArrayStruct Stats; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /.github/workflows/nightly.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Nightly 2 | on: 3 | schedule: 4 | - cron: '0 2 * * *' 5 | workflow_dispatch: 6 | 7 | env: 8 | # Path to the solution file relative to the root of the project. 9 | SOLUTION_FILE_PATH: . 10 | 11 | # Configuration type to build. 12 | # You can convert this to a build matrix if you need coverage of multiple configuration types. 13 | # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 14 | BUILD_CONFIGURATION: Release 15 | 16 | jobs: 17 | nightly-develop: 18 | name: Nightly Develop 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | os: [windows-latest] 23 | runs-on: ${{ matrix.os }} 24 | steps: 25 | - uses: actions/checkout@v2 26 | with: 27 | ref: "develop" 28 | 29 | - name: Add MSBuild to PATH 30 | uses: microsoft/setup-msbuild@v1.0.2 31 | 32 | - name: Restore NuGet packages 33 | working-directory: ${{env.GITHUB_WORKSPACE}} 34 | run: nuget restore ${{env.SOLUTION_FILE_PATH}} 35 | 36 | - name: Build 37 | working-directory: ${{env.GITHUB_WORKSPACE}} 38 | # Add additional options to the MSBuild command line here (like platform or verbosity level). 39 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference 40 | run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}} /p:DebugSymbols=false 41 | 42 | - name: Zip release 43 | uses: papeloto/action-zip@v1 44 | with: 45 | files: bin/x64/Release/ LICENSE README.md 46 | recursive: true 47 | dest: MapAssist.zip 48 | 49 | - name: Publish release 50 | uses: "marvinpinto/action-automatic-releases@latest" 51 | with: 52 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 53 | automatic_release_tag: "develop" 54 | prerelease: false 55 | files: | 56 | LICENSE 57 | README.md 58 | MapAssist.zip 59 | nightly-latest: 60 | name: Nightly Latest 61 | strategy: 62 | fail-fast: false 63 | matrix: 64 | os: [windows-latest] 65 | runs-on: ${{ matrix.os }} 66 | steps: 67 | - uses: actions/checkout@v2 68 | with: 69 | ref: "main" 70 | 71 | - name: Add MSBuild to PATH 72 | uses: microsoft/setup-msbuild@v1.0.2 73 | 74 | - name: Restore NuGet packages 75 | working-directory: ${{env.GITHUB_WORKSPACE}} 76 | run: nuget restore ${{env.SOLUTION_FILE_PATH}} 77 | 78 | - name: Build 79 | working-directory: ${{env.GITHUB_WORKSPACE}} 80 | # Add additional options to the MSBuild command line here (like platform or verbosity level). 81 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference 82 | run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}} /p:DebugSymbols=false 83 | 84 | - name: Zip release 85 | uses: papeloto/action-zip@v1 86 | with: 87 | files: bin/x64/Release/ LICENSE README.md 88 | recursive: true 89 | dest: MapAssist.zip 90 | 91 | - name: Publish release 92 | uses: "marvinpinto/action-automatic-releases@latest" 93 | with: 94 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 95 | automatic_release_tag: "latest" 96 | prerelease: false 97 | files: | 98 | LICENSE 99 | README.md 100 | MapAssist.zip 101 | -------------------------------------------------------------------------------- /Helpers/WindowsExternal.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System; 21 | using System.Runtime.InteropServices; 22 | 23 | namespace MapAssist.Helpers 24 | { 25 | public static class WindowsExternal 26 | { 27 | [DllImport("kernel32.dll", SetLastError = true)] 28 | public static extern IntPtr OpenProcess( 29 | uint processAccess, 30 | bool bInheritHandle, 31 | int processId 32 | ); 33 | 34 | [DllImport("kernel32.dll", SetLastError = true)] 35 | public static extern bool CloseHandle( 36 | IntPtr hObject 37 | ); 38 | 39 | [Flags] 40 | public enum ProcessAccessFlags : uint 41 | { 42 | All = 0x001F0FFF, 43 | Terminate = 0x00000001, 44 | CreateThread = 0x00000002, 45 | VirtualMemoryOperation = 0x00000008, 46 | VirtualMemoryRead = 0x00000010, 47 | VirtualMemoryWrite = 0x00000020, 48 | DuplicateHandle = 0x00000040, 49 | CreateProcess = 0x000000080, 50 | SetQuota = 0x00000100, 51 | SetInformation = 0x00000200, 52 | QueryInformation = 0x00000400, 53 | QueryLimitedInformation = 0x00001000, 54 | Synchronize = 0x00100000 55 | } 56 | 57 | [DllImport("kernel32.dll", SetLastError = true)] 58 | public static extern bool ReadProcessMemory( 59 | IntPtr hProcess, 60 | IntPtr lpBaseAddress, 61 | [Out] byte[] lpBuffer, 62 | int dwSize, 63 | out IntPtr lpNumberOfBytesRead); 64 | 65 | // This helper static method is required because the 32-bit version of user32.dll does not contain this API 66 | // (on any versions of Windows), so linking the method will fail at run-time. The bridge dispatches the request 67 | // to the correct function (GetWindowLong in 32-bit mode and GetWindowLongPtr in 64-bit mode) 68 | 69 | // If that doesn't work, the following signature can be used alternatively. 70 | [DllImport("user32.dll")] 71 | public static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong); 72 | 73 | [DllImport("user32.dll", EntryPoint = "GetWindowLong")] 74 | private static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex); 75 | 76 | [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")] 77 | private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex); 78 | 79 | // This static method is required because Win32 does not support 80 | // GetWindowLongPtr directly 81 | public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex) 82 | { 83 | if (IntPtr.Size == 8) 84 | return GetWindowLongPtr64(hWnd, nIndex); 85 | else 86 | return GetWindowLongPtr32(hWnd, nIndex); 87 | } 88 | 89 | [DllImport("user32.dll")] 90 | [return: MarshalAs(UnmanagedType.Bool)] 91 | public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, 92 | uint uFlags); 93 | 94 | [DllImport("user32.dll")] 95 | public static extern IntPtr GetForegroundWindow(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # The following command works for downloading when using Git for Windows: 2 | # curl -LOf http://gist.githubusercontent.com/kmorcinek/2710267/raw/.gitignore 3 | # 4 | # Download this file using PowerShell v3 under Windows with the following comand: 5 | # Invoke-WebRequest https://gist.githubusercontent.com/kmorcinek/2710267/raw/ -OutFile .gitignore 6 | # 7 | # or wget: 8 | # wget --no-check-certificate http://gist.githubusercontent.com/kmorcinek/2710267/raw/.gitignore 9 | 10 | # User-specific files 11 | *.suo 12 | *.user 13 | *.sln.docstates 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Rr]elease/ 18 | x64/ 19 | [Bb]in/ 20 | [Oo]bj/ 21 | # build folder is nowadays used for build scripts and should not be ignored 22 | #build/ 23 | 24 | # NuGet Packages 25 | *.nupkg 26 | # The packages folder can be ignored because of Package Restore 27 | **/packages/* 28 | # except build/, which is used as an MSBuild target. 29 | !**/packages/build/ 30 | # Uncomment if necessary however generally it will be regenerated when needed 31 | #!**/packages/repositories.config 32 | 33 | # MSTest test Results 34 | [Tt]est[Rr]esult*/ 35 | [Bb]uild[Ll]og.* 36 | 37 | *_i.c 38 | *_p.c 39 | *.ilk 40 | *.meta 41 | *.obj 42 | *.pch 43 | *.pdb 44 | *.pgc 45 | *.pgd 46 | *.rsp 47 | *.sbr 48 | *.tlb 49 | *.tli 50 | *.tlh 51 | *.tmp 52 | *.tmp_proj 53 | *.log 54 | *.vspscc 55 | *.vssscc 56 | .builds 57 | *.pidb 58 | *.log 59 | *.scc 60 | 61 | # OS generated files # 62 | .DS_Store* 63 | Icon? 64 | 65 | # Visual C++ cache files 66 | ipch/ 67 | *.aps 68 | *.ncb 69 | *.opensdf 70 | *.sdf 71 | *.cachefile 72 | 73 | # Visual Studio profiler 74 | *.psess 75 | *.vsp 76 | *.vspx 77 | 78 | # Guidance Automation Toolkit 79 | *.gpState 80 | 81 | # ReSharper is a .NET coding add-in 82 | _ReSharper*/ 83 | *.[Rr]e[Ss]harper 84 | 85 | # TeamCity is a build add-in 86 | _TeamCity* 87 | 88 | # DotCover is a Code Coverage Tool 89 | *.dotCover 90 | 91 | # NCrunch 92 | *.ncrunch* 93 | .*crunch*.local.xml 94 | 95 | # Installshield output folder 96 | [Ee]xpress/ 97 | 98 | # DocProject is a documentation generator add-in 99 | DocProject/buildhelp/ 100 | DocProject/Help/*.HxT 101 | DocProject/Help/*.HxC 102 | DocProject/Help/*.hhc 103 | DocProject/Help/*.hhk 104 | DocProject/Help/*.hhp 105 | DocProject/Help/Html2 106 | DocProject/Help/html 107 | 108 | # Click-Once directory 109 | publish/ 110 | 111 | # Publish Web Output 112 | *.Publish.xml 113 | 114 | # Windows Azure Build Output 115 | csx 116 | *.build.csdef 117 | 118 | # Windows Store app package directory 119 | AppPackages/ 120 | 121 | # Others 122 | *.Cache 123 | ClientBin/ 124 | [Ss]tyle[Cc]op.* 125 | ~$* 126 | *~ 127 | *.dbmdl 128 | *.[Pp]ublish.xml 129 | *.pfx 130 | *.publishsettings 131 | modulesbin/ 132 | tempbin/ 133 | 134 | # EPiServer Site file (VPP) 135 | AppData/ 136 | 137 | # RIA/Silverlight projects 138 | Generated_Code/ 139 | 140 | # Backup & report files from converting an old project file to a newer 141 | # Visual Studio version. Backup files are not needed, because we have git ;-) 142 | _UpgradeReport_Files/ 143 | Backup*/ 144 | UpgradeLog*.XML 145 | UpgradeLog*.htm 146 | 147 | # vim 148 | *.txt~ 149 | *.swp 150 | *.swo 151 | 152 | # Temp files when opening LibreOffice on ubuntu 153 | .~lock.* 154 | 155 | # svn 156 | .svn 157 | 158 | # CVS - Source Control 159 | **/CVS/ 160 | 161 | # Remainings from resolving conflicts in Source Control 162 | *.orig 163 | 164 | # SQL Server files 165 | **/App_Data/*.mdf 166 | **/App_Data/*.ldf 167 | **/App_Data/*.sdf 168 | 169 | 170 | #LightSwitch generated files 171 | GeneratedArtifacts/ 172 | _Pvt_Extensions/ 173 | ModelManifest.xml 174 | 175 | # ========================= 176 | # Windows detritus 177 | # ========================= 178 | 179 | # Windows image file caches 180 | Thumbs.db 181 | ehthumbs.db 182 | 183 | # Folder config file 184 | Desktop.ini 185 | 186 | # Recycle Bin used on file shares 187 | $RECYCLE.BIN/ 188 | 189 | # Mac desktop service store files 190 | .DS_Store 191 | 192 | # SASS Compiler cache 193 | .sass-cache 194 | 195 | # Visual Studio 2014 CTP 196 | **/*.sln.ide 197 | 198 | # Visual Studio temp something 199 | .vs/ 200 | 201 | # dotnet stuff 202 | project.lock.json 203 | 204 | # VS 2015+ 205 | *.vc.vc.opendb 206 | *.vc.db 207 | 208 | # Rider 209 | .idea/ 210 | 211 | # Visual Studio Code 212 | .vscode/ 213 | 214 | # Output folder used by Webpack or other FE stuff 215 | **/node_modules/* 216 | **/wwwroot/* 217 | 218 | # SpecFlow specific 219 | *.feature.cs 220 | *.feature.xlsx.* 221 | *.Specs_*.html 222 | 223 | ##### 224 | # End of core ignore list, below put you custom 'per project' settings (patterns or path) 225 | ##### 226 | -------------------------------------------------------------------------------- /Types/RawAreaData.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Collections.Generic; 21 | using System.Drawing; 22 | using System.Linq; 23 | 24 | // ReSharper disable ClassNeverInstantiated.Global 25 | // ReSharper disable InconsistentNaming 26 | // ReSharper disable MemberCanBePrivate.Global 27 | // ReSharper disable UnassignedField.Global 28 | // ReSharper disable CollectionNeverUpdated.Global 29 | 30 | namespace MapAssist.Types 31 | { 32 | public class XY 33 | { 34 | public int x; 35 | public int y; 36 | 37 | public Point ToPoint() 38 | { 39 | return new Point(x, y); 40 | } 41 | } 42 | 43 | public class RawAdjacentLevel 44 | { 45 | public XY[] exits; 46 | public XY origin; 47 | public int width; 48 | public int height; 49 | 50 | public AdjacentLevel ToInternal(Area area) 51 | { 52 | return new AdjacentLevel 53 | { 54 | Area = area, 55 | Origin = origin.ToPoint(), 56 | Exits = exits.Select(o => o.ToPoint()).ToArray(), 57 | Width = width, 58 | Height = height, 59 | }; 60 | } 61 | } 62 | 63 | public class RawAreaData 64 | { 65 | public XY levelOrigin; 66 | public Dictionary adjacentLevels; 67 | public int[][] mapRows; 68 | public Dictionary npcs; 69 | public Dictionary objects; 70 | 71 | public AreaData ToInternal(Area area) 72 | { 73 | return new AreaData 74 | { 75 | Area = area, 76 | Origin = levelOrigin.ToPoint(), 77 | AdjacentLevels = adjacentLevels 78 | .Select(o => 79 | { 80 | var adjacentArea = Area.None; 81 | if (int.TryParse(o.Key, out int parsed)) 82 | { 83 | adjacentArea = (Area)parsed; 84 | } 85 | 86 | AdjacentLevel level = o.Value.ToInternal(adjacentArea); 87 | return (adjacentArea, level); 88 | }) 89 | .Where(o => o.adjacentArea != Area.None) 90 | .ToDictionary(k => k.adjacentArea, v => v.level), 91 | NPCs = npcs.Select(o => 92 | { 93 | Point[] positions = o.Value.Select(j => j.ToPoint()).ToArray(); 94 | var npc = Npc.Invalid; 95 | if (int.TryParse(o.Key, out int parsed)) 96 | { 97 | npc = (Npc)parsed; 98 | } 99 | 100 | return (npc, positions); 101 | }) 102 | .Where(o => o.npc != Npc.Invalid) 103 | .ToDictionary(k => k.npc, v => v.positions), 104 | Objects = objects.Select(o => 105 | { 106 | Point[] positions = o.Value.Select(j => j.ToPoint()).ToArray(); 107 | var gameObject = GameObject.NotApplicable; 108 | if (int.TryParse(o.Key, out int parsed)) 109 | { 110 | gameObject = (GameObject)parsed; 111 | } 112 | 113 | return (gameObject, positions); 114 | }) 115 | .Where(o => o.gameObject != GameObject.NotApplicable) 116 | .ToDictionary(k => k.gameObject, v => v.positions), 117 | CollisionGrid = mapRows 118 | }; 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Settings/Utils.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System; 21 | using System.Configuration; 22 | using System.Diagnostics; 23 | using System.Drawing; 24 | using System.Linq; 25 | using MapAssist.Types; 26 | 27 | namespace MapAssist.Settings 28 | { 29 | public static class Utils 30 | { 31 | public static string[] ParseCommaSeparatedNpcsByName(string npc) 32 | { 33 | return npc 34 | .Split(',') 35 | .Select(o => LookupNpcByName(o.Trim())) 36 | .Where(o => o != "") 37 | .ToArray(); 38 | } 39 | public static Area[] ParseCommaSeparatedAreasByName(string areas) 40 | { 41 | return areas 42 | .Split(',') 43 | .Select(o => LookupAreaByName(o.Trim())) 44 | .Where(o => o != Area.None) 45 | .ToArray(); 46 | } 47 | 48 | private static string LookupNpcByName(string name) 49 | { 50 | var name2 = ""; 51 | try 52 | { 53 | name2 = Enum.GetName(typeof(Npc), name); 54 | } 55 | catch 56 | { 57 | return name; 58 | } 59 | return name2; 60 | } 61 | private static Area LookupAreaByName(string name) 62 | { 63 | return Enum.GetValues(typeof(Area)).Cast().FirstOrDefault(area => area.Name() == name); 64 | } 65 | 66 | private static T GetConfigValue(string key, Func converter, T fallback = default) 67 | { 68 | string valueString = ConfigurationManager.AppSettings[key]; 69 | return string.IsNullOrWhiteSpace(valueString) ? fallback : converter.Invoke(valueString); 70 | } 71 | 72 | public static Color ParseColor(string value) 73 | { 74 | if (value.StartsWith("#")) 75 | { 76 | return ColorTranslator.FromHtml(value); 77 | } 78 | 79 | if (!value.Contains(",")) 80 | { 81 | return Color.FromName(value); 82 | } 83 | 84 | int[] ints = value.Split(',').Select(o => int.Parse(o.Trim())).ToArray(); 85 | switch (ints.Length) 86 | { 87 | case 4: 88 | return Color.FromArgb(ints[0], ints[1], ints[2], ints[3]); 89 | case 3: 90 | return Color.FromArgb(ints[0], ints[1], ints[2]); 91 | } 92 | 93 | return Color.FromName(value); 94 | } 95 | 96 | public static PointOfInterestRendering GetRenderingSettingsForPrefix(string name) 97 | { 98 | return new PointOfInterestRendering 99 | { 100 | IconColor = GetConfigValue($"{name}.IconColor", ParseColor, Color.Transparent), 101 | IconShape = GetConfigValue($"{name}.IconShape", t => (Shape)Enum.Parse(typeof(Shape), t, true)), 102 | IconSize = GetConfigValue($"{name}.IconSize", Convert.ToInt32), 103 | LineColor = GetConfigValue($"{name}.LineColor", ParseColor, Color.Transparent), 104 | LineThickness = GetConfigValue($"{name}.LineThickness", Convert.ToSingle, 1), 105 | ArrowHeadSize = GetConfigValue($"{name}.ArrowHeadSize", Convert.ToInt32), 106 | LabelColor = GetConfigValue($"{name}.LabelColor", ParseColor, Color.Transparent), 107 | LabelFont = GetConfigValue($"{name}.LabelFont", t => t, "Arial"), 108 | LabelFontSize = GetConfigValue($"{name}.LabelFontSize", Convert.ToInt32, 8), 109 | }; 110 | } 111 | public static MobRendering GetMobRendering() 112 | { 113 | return new MobRendering 114 | { 115 | NormalColor = GetConfigValue($"MobColor.Normal", ParseColor, Color.Transparent), 116 | UniqueColor = GetConfigValue($"MobColor.Unique", ParseColor, Color.Transparent) 117 | }; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 100 | 101 | 102 | 103 | 104 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /Settings/Settings.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Configuration; 23 | using System.Drawing; 24 | using MapAssist.Types; 25 | 26 | // ReSharper disable FieldCanBeMadeReadOnly.Global 27 | 28 | namespace MapAssist.Settings 29 | { 30 | public static class Rendering 31 | { 32 | public static PointOfInterestRendering 33 | NextArea = Utils.GetRenderingSettingsForPrefix("NextArea"); 34 | 35 | public static PointOfInterestRendering PreviousArea = 36 | Utils.GetRenderingSettingsForPrefix("PreviousArea"); 37 | 38 | public static PointOfInterestRendering Waypoint = Utils.GetRenderingSettingsForPrefix("Waypoint"); 39 | public static PointOfInterestRendering Quest = Utils.GetRenderingSettingsForPrefix("Quest"); 40 | public static PointOfInterestRendering Player = Utils.GetRenderingSettingsForPrefix("Player"); 41 | 42 | public static PointOfInterestRendering SuperChest = 43 | Utils.GetRenderingSettingsForPrefix("SuperChest"); 44 | } 45 | 46 | public static class Map 47 | { 48 | public static readonly Dictionary MapColors = new Dictionary(); 49 | 50 | public static void InitMapColors() 51 | { 52 | for (var i = -1; i < 600; i++) 53 | { 54 | LookupMapColor(i); 55 | } 56 | } 57 | 58 | public static Color? LookupMapColor(int type) 59 | { 60 | var key = "MapColor[" + type + "]"; 61 | 62 | if (!MapColors.ContainsKey(type)) 63 | { 64 | var mapColorString = ConfigurationManager.AppSettings[key]; 65 | if (!string.IsNullOrEmpty(mapColorString)) 66 | { 67 | MapColors[type] = Utils.ParseColor(mapColorString); 68 | } 69 | else 70 | { 71 | MapColors[type] = null; 72 | } 73 | } 74 | 75 | return MapColors[type]; 76 | } 77 | 78 | public static double Opacity = Convert.ToDouble(ConfigurationManager.AppSettings["Opacity"], 79 | System.Globalization.CultureInfo.InvariantCulture); 80 | 81 | public static bool OverlayMode = Convert.ToBoolean(ConfigurationManager.AppSettings["OverlayMode"]); 82 | 83 | public static bool AlwaysOnTop = Convert.ToBoolean(ConfigurationManager.AppSettings["AlwaysOnTop"]); 84 | 85 | public static bool ToggleViaInGameMap = 86 | Convert.ToBoolean(ConfigurationManager.AppSettings["ToggleViaInGameMap"]); 87 | 88 | public static int Size = Convert.ToInt16(ConfigurationManager.AppSettings["Size"]); 89 | 90 | public static MapPosition Position = 91 | (MapPosition)Enum.Parse(typeof(MapPosition), ConfigurationManager.AppSettings["MapPosition"], true); 92 | 93 | public static int UpdateTime = Convert.ToInt16(ConfigurationManager.AppSettings["UpdateTime"]); 94 | public static bool Rotate = Convert.ToBoolean(ConfigurationManager.AppSettings["Rotate"]); 95 | public static char ToggleKey = Convert.ToChar(ConfigurationManager.AppSettings["ToggleKey"]); 96 | public static char ZoomInKey = Convert.ToChar(ConfigurationManager.AppSettings["ZoomInKey"]); 97 | public static char ZoomOutKey = Convert.ToChar(ConfigurationManager.AppSettings["ZoomOutKey"]); 98 | public static float ZoomLevel = Convert.ToSingle(ConfigurationManager.AppSettings["ZoomLevelDefault"]); 99 | 100 | public static Area[] PrefetchAreas = 101 | Utils.ParseCommaSeparatedAreasByName(ConfigurationManager.AppSettings["PrefetchAreas"]); 102 | 103 | public static Area[] HiddenAreas = 104 | Utils.ParseCommaSeparatedAreasByName(ConfigurationManager.AppSettings["HiddenAreas"]); 105 | 106 | public static string[] WarnImmuneNPC = 107 | Utils.ParseCommaSeparatedNpcsByName(ConfigurationManager.AppSettings["WarnNPCImmune"]); 108 | public static int WarnImmuneNPCFontSize = Convert.ToInt32(ConfigurationManager.AppSettings["WarnNPCFontSize"]); 109 | public static string WarnImmuneNPCFont = Convert.ToString(ConfigurationManager.AppSettings["WarnNPCFont"]); 110 | public static StringAlignment WarnNPCVerticalAlign = (StringAlignment)Enum.Parse(typeof(StringAlignment), ConfigurationManager.AppSettings["WarnNPCVerticalAlign"]); 111 | public static StringAlignment WarnNPCHorizontalAlign = (StringAlignment)Enum.Parse(typeof(StringAlignment), ConfigurationManager.AppSettings["WarnNPCHorizontalAlign"]); 112 | public static Color WarnNPCFontColor = Utils.ParseColor(Convert.ToString(ConfigurationManager.AppSettings["WarnNPCFontColor"])); 113 | 114 | public static bool ClearPrefetchedOnAreaChange = 115 | Convert.ToBoolean(ConfigurationManager.AppSettings["ClearPrefetchedOnAreaChange"]); 116 | } 117 | 118 | public static class Api 119 | { 120 | public static string Endpoint = ConfigurationManager.AppSettings["ApiEndpoint"]; 121 | public static string Token = ConfigurationManager.AppSettings["ApiToken"]; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /Helpers/MapApi.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using MapAssist.Types; 21 | using Newtonsoft.Json; 22 | using System; 23 | using System.Collections.Concurrent; 24 | using System.Collections.Generic; 25 | using System.Diagnostics.CodeAnalysis; 26 | using System.Linq; 27 | using System.Net; 28 | using System.Net.Http; 29 | using System.Net.Http.Headers; 30 | using System.Text; 31 | using System.Threading; 32 | #pragma warning disable 649 33 | 34 | namespace MapAssist.Helpers 35 | { 36 | public class MapApi : IDisposable 37 | { 38 | public static readonly HttpClient Client = HttpClient(Settings.Api.Endpoint, Settings.Api.Token); 39 | private readonly string _sessionId; 40 | private readonly ConcurrentDictionary _cache; 41 | private readonly BlockingCollection _prefetchRequests; 42 | private readonly Thread _thread; 43 | private readonly HttpClient _client; 44 | 45 | private string CreateSession(Difficulty difficulty, uint mapSeed) 46 | { 47 | var values = new Dictionary 48 | { 49 | { "difficulty", (uint)difficulty }, 50 | { "mapid", mapSeed } 51 | }; 52 | 53 | var json = JsonConvert.SerializeObject(values); 54 | var content = new StringContent(json, Encoding.UTF8, "application/json"); 55 | HttpResponseMessage response = _client.PostAsync("sessions/", content).GetAwaiter().GetResult(); 56 | response.EnsureSuccessStatusCode(); 57 | var session = 58 | JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().GetAwaiter() 59 | .GetResult()); 60 | return session.id; 61 | } 62 | 63 | private void DestroySession(string sessionId) 64 | { 65 | HttpResponseMessage response = 66 | _client.DeleteAsync("sessions/" + sessionId).GetAwaiter().GetResult(); 67 | response.EnsureSuccessStatusCode(); 68 | } 69 | 70 | public MapApi(HttpClient client, Difficulty difficulty, uint mapSeed) 71 | { 72 | _client = client; 73 | _sessionId = CreateSession(difficulty, mapSeed); 74 | // Cache for pre-fetching maps for the surrounding areas. 75 | _cache = new ConcurrentDictionary(); 76 | _prefetchRequests = new BlockingCollection(); 77 | _thread = new Thread(Prefetch) 78 | { 79 | IsBackground = true 80 | }; 81 | _thread.Start(); 82 | 83 | if (Settings.Map.PrefetchAreas.Any()) 84 | { 85 | _prefetchRequests.Add(Settings.Map.PrefetchAreas); 86 | } 87 | } 88 | 89 | public AreaData GetMapData(Area area) 90 | { 91 | if (!_cache.TryGetValue(area, out AreaData areaData)) 92 | { 93 | // Not in the cache, block. 94 | Console.WriteLine($"Cache miss on {area}"); 95 | areaData = GetMapDataInternal(area); 96 | } 97 | 98 | Area[] adjacentAreas = areaData.AdjacentLevels.Keys.ToArray(); 99 | if (adjacentAreas.Any()) 100 | { 101 | _prefetchRequests.Add(adjacentAreas); 102 | } 103 | 104 | return areaData; 105 | } 106 | 107 | private void Prefetch() 108 | { 109 | while (true) 110 | { 111 | Area[] areas = _prefetchRequests.Take(); 112 | if (Settings.Map.ClearPrefetchedOnAreaChange) 113 | { 114 | _cache.Clear(); 115 | } 116 | 117 | // Special value telling us to exit. 118 | if (areas.Length == 0) 119 | { 120 | Console.WriteLine("Prefetch thread terminating"); 121 | return; 122 | } 123 | 124 | foreach (Area area in areas) 125 | { 126 | if (_cache.ContainsKey(area)) continue; 127 | 128 | _cache[area] = GetMapDataInternal(area); 129 | Console.WriteLine($"Prefetched {area}"); 130 | } 131 | } 132 | } 133 | 134 | private AreaData GetMapDataInternal(Area area) 135 | { 136 | HttpResponseMessage response = _client.GetAsync("sessions/" + _sessionId + 137 | "/areas/" + (uint)area).GetAwaiter().GetResult(); 138 | response.EnsureSuccessStatusCode(); 139 | var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); 140 | var rawMapData = JsonConvert.DeserializeObject(content); 141 | return rawMapData.ToInternal(area); 142 | } 143 | 144 | private static HttpClient HttpClient(string endpoint, string token) 145 | { 146 | var client = new HttpClient(new HttpClientHandler 147 | { 148 | AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate 149 | }) 150 | { 151 | BaseAddress = new Uri(endpoint) 152 | }; 153 | client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*")); 154 | client.DefaultRequestHeaders.AcceptEncoding.Add( 155 | new StringWithQualityHeaderValue("gzip")); 156 | client.DefaultRequestHeaders.AcceptEncoding.Add( 157 | new StringWithQualityHeaderValue("deflate")); 158 | if (!string.IsNullOrEmpty(token)) 159 | { 160 | client.DefaultRequestHeaders.Authorization = 161 | new AuthenticationHeaderValue("Bearer", token); 162 | } 163 | return client; 164 | } 165 | 166 | public void Dispose() 167 | { 168 | _prefetchRequests.Add(new Area[] { }); 169 | _thread.Join(); 170 | try 171 | { 172 | DestroySession(_sessionId); 173 | } 174 | catch (HttpRequestException) // Prevent HttpRequestException if D2MapAPI is closed before this program. 175 | { 176 | Console.WriteLine("D2MapAPI server was closed, session was already destroyed."); 177 | } 178 | } 179 | 180 | [SuppressMessage("ReSharper", "InconsistentNaming")] 181 | [SuppressMessage("CodeQuality", "IDE0079:Remove unnecessary suppression", Justification = "ReSharper")] 182 | private class MapApiSession 183 | { 184 | public string id; 185 | public uint difficulty; 186 | public uint mapId; 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /MapAssist.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | win-x64 6 | $([System.Guid]::NewGuid()) 7 | Release 8 | x64 9 | {FB3AC437-B7BB-42FF-A2A2-F10551F95F6C} 10 | WinExe 11 | MapAssist 12 | 13 | 14 | $(CustomAssemblyName) 15 | $(RandomGuid) 16 | MapAssist 17 | v4.7.2 18 | 512 19 | true 20 | true 21 | false 22 | publish\ 23 | true 24 | Disk 25 | false 26 | Foreground 27 | 7 28 | Days 29 | false 30 | false 31 | true 32 | 1 33 | 1.0.0.%2a 34 | false 35 | true 36 | true 37 | 38 | 39 | true 40 | bin\x64\Debug\ 41 | DEBUG;TRACE 42 | full 43 | x64 44 | 7.3 45 | prompt 46 | false 47 | true 48 | 49 | 50 | bin\x64\Release\ 51 | TRACE 52 | true 53 | none 54 | x64 55 | 7.3 56 | prompt 57 | false 58 | true 59 | 60 | 61 | 3DB9B26A33D3BC5805AF01B7BC6B71FE986ABD87 62 | 63 | 64 | MapAssist_TemporaryKey.pfx 65 | 66 | 67 | false 68 | 69 | 70 | false 71 | 72 | 73 | true 74 | 75 | 76 | 77 | 78 | 79 | 80 | false 81 | 82 | 83 | LocalIntranet 84 | 85 | 86 | 87 | Resources\Icon1.ico 88 | 89 | 90 | 91 | true 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | Form 112 | 113 | 114 | Overlay.cs 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | Overlay.cs 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | False 161 | Microsoft .NET Framework 4.7.2 %28x86 and x64%29 162 | true 163 | 164 | 165 | False 166 | .NET Framework 3.5 SP1 167 | false 168 | 169 | 170 | 171 | 172 | 5.6.0 173 | 174 | 175 | 13.0.1 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /Helpers/PointOfInterestHandler.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Collections.Generic; 21 | using System.Drawing; 22 | using System.Linq; 23 | using System.Threading.Tasks; 24 | using MapAssist.Types; 25 | 26 | namespace MapAssist.Helpers 27 | { 28 | public static class PointOfInterestHandler 29 | { 30 | private static readonly HashSet QuestObjects = new HashSet 31 | { 32 | GameObject.HoradricCubeChest, 33 | GameObject.HoradricScrollChest, 34 | GameObject.StaffOfKingsChest, 35 | GameObject.HoradricOrifice, 36 | GameObject.YetAnotherTome, // Summoner in Arcane Sanctuary 37 | GameObject.FrozenAnya, 38 | GameObject.InifussTree, 39 | GameObject.CairnStoneAlpha, 40 | GameObject.WirtCorpse, 41 | GameObject.HellForge 42 | }; 43 | 44 | private static readonly HashSet GoodChests = new HashSet 45 | { 46 | GameObject.GoodChest, 47 | GameObject.SparklyChest, 48 | GameObject.ArcaneLargeChestLeft, 49 | GameObject.ArcaneLargeChestRight, 50 | GameObject.ArcaneSmallChestLeft, 51 | GameObject.ArcaneSmallChestRight 52 | }; 53 | 54 | public static List Get(MapApi mapApi, AreaData areaData) 55 | { 56 | List pointOfInterest = new List(); 57 | 58 | switch (areaData.Area) 59 | { 60 | case Area.CanyonOfTheMagi: 61 | // Work out which tomb is the right once. 62 | // Load the maps for all of the tombs, and check which one has the Orifice. 63 | // Declare that tomb as point of interest. 64 | Area[] tombs = new[] 65 | { 66 | Area.TalRashasTomb1, Area.TalRashasTomb2, Area.TalRashasTomb3, Area.TalRashasTomb4, 67 | Area.TalRashasTomb5, Area.TalRashasTomb6, Area.TalRashasTomb7 68 | }; 69 | var realTomb = Area.None; 70 | Parallel.ForEach(tombs, tombArea => 71 | { 72 | AreaData tombData = mapApi.GetMapData(tombArea); 73 | if (tombData.Objects.ContainsKey(GameObject.HoradricOrifice)) 74 | { 75 | realTomb = tombArea; 76 | } 77 | }); 78 | 79 | if (realTomb != Area.None && areaData.AdjacentLevels[realTomb].Exits.Any()) 80 | { 81 | pointOfInterest.Add(new PointOfInterest 82 | { 83 | Label = realTomb.Name(), 84 | Position = areaData.AdjacentLevels[realTomb].Exits[0], 85 | RenderingSettings = Settings.Rendering.NextArea 86 | }); ; 87 | } 88 | 89 | break; 90 | default: 91 | // By default, draw a line to the next highest neighbouring area. 92 | // Also draw labels and previous doors for all other areas. 93 | if (areaData.AdjacentLevels.Any()) 94 | { 95 | Area highestArea = areaData.AdjacentLevels.Keys.Max(); 96 | if (highestArea > areaData.Area) 97 | { 98 | if (areaData.AdjacentLevels[highestArea].Exits.Any()) 99 | { 100 | pointOfInterest.Add(new PointOfInterest 101 | { 102 | Label = highestArea.Name(), 103 | Position = areaData.AdjacentLevels[highestArea].Exits[0], 104 | RenderingSettings = Settings.Rendering.NextArea 105 | }); 106 | } 107 | } 108 | 109 | foreach (AdjacentLevel level in areaData.AdjacentLevels.Values) 110 | { 111 | // Already have something drawn for this. 112 | if (level.Area == highestArea) 113 | { 114 | continue; 115 | } 116 | 117 | foreach (Point position in level.Exits) 118 | { 119 | pointOfInterest.Add(new PointOfInterest 120 | { 121 | Label = level.Area.Name(), 122 | Position = position, 123 | RenderingSettings = Settings.Rendering.PreviousArea 124 | }); 125 | } 126 | } 127 | } 128 | 129 | break; 130 | } 131 | 132 | foreach (KeyValuePair objAndPoints in areaData.Objects) 133 | { 134 | GameObject obj = objAndPoints.Key; 135 | Point[] points = objAndPoints.Value; 136 | 137 | if (!points.Any()) 138 | { 139 | continue; 140 | } 141 | 142 | // Waypoints 143 | if (obj.IsWaypoint()) 144 | { 145 | pointOfInterest.Add(new PointOfInterest 146 | { 147 | Label = obj.ToString(), 148 | Position = points[0], 149 | RenderingSettings = Settings.Rendering.Waypoint 150 | }); 151 | } 152 | // Quest objects 153 | else if (QuestObjects.Contains(obj)) 154 | { 155 | pointOfInterest.Add(new PointOfInterest 156 | { 157 | Label = obj.ToString(), 158 | Position = points[0], 159 | RenderingSettings = Settings.Rendering.Quest 160 | }); 161 | } 162 | // Chests 163 | else if (GoodChests.Contains(obj)) 164 | { 165 | foreach (Point point in points) 166 | { 167 | pointOfInterest.Add(new PointOfInterest 168 | { 169 | Label = obj.ToString(), 170 | Position = point, 171 | RenderingSettings = Settings.Rendering.SuperChest 172 | }); 173 | } 174 | } 175 | switch (areaData.Area) 176 | { 177 | case Area.HallsOfVaught: 178 | if (obj == GameObject.NihlathakWildernessStartPosition) 179 | { 180 | pointOfInterest.Add(new PointOfInterest 181 | { 182 | Label = obj.ToString(), 183 | Position = points[0], 184 | RenderingSettings = Settings.Rendering.Quest 185 | }); 186 | } 187 | break; 188 | } 189 | } 190 | 191 | return pointOfInterest; 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /Helpers/ImageUtils.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System; 21 | using System.Diagnostics; 22 | using System.Drawing.Drawing2D; 23 | using System.Drawing.Imaging; 24 | using System.Drawing; 25 | 26 | namespace MapAssist.Helpers 27 | { 28 | public static class ImageUtils 29 | { 30 | public static Bitmap RotateImage(Image inputImage, float angleDegrees, bool upsizeOk, bool clipOk, 31 | Color backgroundColor) 32 | { 33 | // Test for zero rotation and return a clone of the input image 34 | if (angleDegrees == 0f) 35 | return (Bitmap)inputImage.Clone(); 36 | 37 | // Set up old and new image dimensions, assuming upsizing not wanted and clipping OK 38 | int oldWidth = inputImage.Width; 39 | int oldHeight = inputImage.Height; 40 | int newWidth = oldWidth; 41 | int newHeight = oldHeight; 42 | var scaleFactor = 1f; 43 | 44 | // If upsizing wanted or clipping not OK calculate the size of the resulting bitmap 45 | if (upsizeOk || !clipOk) 46 | { 47 | double angleRadians = angleDegrees * Math.PI / 180d; 48 | 49 | double cos = Math.Abs(Math.Cos(angleRadians)); 50 | double sin = Math.Abs(Math.Sin(angleRadians)); 51 | newWidth = (int)Math.Round(oldWidth * cos + oldHeight * sin); 52 | newHeight = (int)Math.Round(oldWidth * sin + oldHeight * cos); 53 | } 54 | 55 | // If upsizing not wanted and clipping not OK need a scaling factor 56 | if (!upsizeOk && !clipOk) 57 | { 58 | scaleFactor = Math.Min((float)oldWidth / newWidth, (float)oldHeight / newHeight); 59 | newWidth = oldWidth; 60 | newHeight = oldHeight; 61 | } 62 | 63 | // Create the new bitmap object. If background color is transparent it must be 32-bit, 64 | // otherwise 24-bit is good enough. 65 | var newBitmap = new Bitmap(newWidth, newHeight, 66 | backgroundColor == Color.Transparent ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb); 67 | newBitmap.SetResolution(inputImage.HorizontalResolution, inputImage.VerticalResolution); 68 | 69 | // Create the Graphics object that does the work 70 | using (Graphics graphicsObject = Graphics.FromImage(newBitmap)) 71 | { 72 | graphicsObject.InterpolationMode = InterpolationMode.HighQualityBicubic; 73 | graphicsObject.PixelOffsetMode = PixelOffsetMode.HighQuality; 74 | graphicsObject.SmoothingMode = SmoothingMode.HighQuality; 75 | 76 | // Fill in the specified background color if necessary 77 | if (backgroundColor != Color.Transparent) 78 | graphicsObject.Clear(backgroundColor); 79 | 80 | // Set up the built-in transformation matrix to do the rotation and maybe scaling 81 | graphicsObject.TranslateTransform(newWidth / 2f, newHeight / 2f); 82 | 83 | if (scaleFactor != 1f) 84 | graphicsObject.ScaleTransform(scaleFactor, scaleFactor); 85 | 86 | graphicsObject.RotateTransform(angleDegrees); 87 | graphicsObject.TranslateTransform(-oldWidth / 2f, -oldHeight / 2f); 88 | 89 | // Draw the result 90 | graphicsObject.DrawImage(inputImage, 0, 0); 91 | } 92 | 93 | return newBitmap; 94 | } 95 | 96 | public static (Bitmap, Point) CropBitmap(Bitmap originalBitmap) 97 | { 98 | // Find the min/max non-white/transparent pixels 99 | var min = new Point(int.MaxValue, int.MaxValue); 100 | var max = new Point(int.MinValue, int.MinValue); 101 | 102 | unsafe 103 | { 104 | var bData = originalBitmap.LockBits(new Rectangle(0, 0, originalBitmap.Width, originalBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 105 | byte bitsPerPixel = 32; 106 | byte* scan0 = (byte*)bData.Scan0.ToPointer(); 107 | 108 | for (int y = 0; y < bData.Height; ++y) 109 | { 110 | for (int x = 0; x < bData.Width; ++x) 111 | { 112 | byte* data = scan0 + y * bData.Stride + x * bitsPerPixel / 8; 113 | // data[0 = blue, 1 = green, 2 = red, 3 = alpha] 114 | if (data[3] == byte.MaxValue) 115 | { 116 | if (x < min.X) min.X = x; 117 | if (y < min.Y) min.Y = y; 118 | 119 | if (x > max.X) max.X = x; 120 | if (y > max.Y) max.Y = y; 121 | } 122 | } 123 | } 124 | originalBitmap.UnlockBits(bData); 125 | } 126 | 127 | // Create a new bitmap from the crop rectangle 128 | var cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X, max.Y - min.Y); 129 | var newBitmap = new Bitmap(cropRectangle.Width, cropRectangle.Height); 130 | using (Graphics g = Graphics.FromImage(newBitmap)) 131 | { 132 | g.DrawImage(originalBitmap, 0, 0, cropRectangle, GraphicsUnit.Pixel); 133 | } 134 | 135 | return (newBitmap, min); 136 | } 137 | 138 | /// 139 | /// Resize the image to the specified width and height. 140 | /// 141 | /// The image to resize. 142 | /// The width to resize to. 143 | /// The height to resize to. 144 | /// The resized image. 145 | public static Bitmap ResizeImage(Image image, int width, int height) 146 | { 147 | var destRect = new Rectangle(0, 0, width, height); 148 | var destImage = new Bitmap(width, height); 149 | 150 | destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution); 151 | 152 | using (Graphics graphics = Graphics.FromImage(destImage)) 153 | { 154 | graphics.CompositingMode = CompositingMode.SourceCopy; 155 | graphics.CompositingQuality = CompositingQuality.HighQuality; 156 | graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; 157 | graphics.SmoothingMode = SmoothingMode.HighQuality; 158 | graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; 159 | 160 | using (var wrapMode = new ImageAttributes()) 161 | { 162 | wrapMode.SetWrapMode(WrapMode.TileFlipXY); 163 | graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode); 164 | } 165 | } 166 | 167 | return destImage; 168 | } 169 | 170 | public static Bitmap CreateFilledRectangle(Color color, int width, int height) 171 | { 172 | var rectangle = new Bitmap(width, height, PixelFormat.Format32bppArgb); 173 | Graphics graphics = Graphics.FromImage(rectangle); 174 | graphics.SmoothingMode = SmoothingMode.AntiAlias; 175 | graphics.FillRectangle(new SolidBrush(color), 0, 0, width, height); 176 | graphics.Dispose(); 177 | return rectangle; 178 | } 179 | 180 | public static Bitmap CreateFilledEllipse(Color color, int width, int height) 181 | { 182 | var ellipse = new Bitmap(width, height, PixelFormat.Format32bppArgb); 183 | Graphics graphics = Graphics.FromImage(ellipse); 184 | graphics.SmoothingMode = SmoothingMode.AntiAlias; 185 | graphics.FillEllipse(new SolidBrush(color), 0, 0, width, height); 186 | graphics.Dispose(); 187 | return ellipse; 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Remove the line below if you want to inherit .editorconfig settings from higher directories 2 | root = true 3 | 4 | # C# files 5 | [*.cs] 6 | 7 | #### Core EditorConfig Options #### 8 | 9 | # Indentation and spacing 10 | indent_size = 4 11 | indent_style = space 12 | tab_width = 4 13 | 14 | # New line preferences 15 | end_of_line = crlf 16 | insert_final_newline = true 17 | 18 | #### .NET Coding Conventions #### 19 | 20 | # Organize usings 21 | dotnet_separate_import_directive_groups = false 22 | dotnet_sort_system_directives_first = false 23 | file_header_template = unset 24 | 25 | # this. and Me. preferences 26 | dotnet_style_qualification_for_event = false:error 27 | dotnet_style_qualification_for_field = false:error 28 | dotnet_style_qualification_for_method = false:error 29 | dotnet_style_qualification_for_property = false:error 30 | 31 | # Language keywords vs BCL types preferences 32 | dotnet_style_predefined_type_for_locals_parameters_members = true:error 33 | dotnet_style_predefined_type_for_member_access = true:error 34 | 35 | # Parentheses preferences 36 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity 37 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity 38 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary 39 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity 40 | 41 | # Modifier preferences 42 | dotnet_style_require_accessibility_modifiers = for_non_interface_members 43 | 44 | # Expression-level preferences 45 | dotnet_style_coalesce_expression = true 46 | dotnet_style_collection_initializer = true 47 | dotnet_style_explicit_tuple_names = true 48 | dotnet_style_null_propagation = true 49 | dotnet_style_object_initializer = true 50 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 51 | dotnet_style_prefer_auto_properties = true 52 | dotnet_style_prefer_compound_assignment = true 53 | dotnet_style_prefer_conditional_expression_over_assignment = true 54 | dotnet_style_prefer_conditional_expression_over_return = true 55 | dotnet_style_prefer_inferred_anonymous_type_member_names = true 56 | dotnet_style_prefer_inferred_tuple_names = true 57 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true 58 | dotnet_style_prefer_simplified_boolean_expressions = true 59 | dotnet_style_prefer_simplified_interpolation = true 60 | 61 | # Field preferences 62 | dotnet_style_readonly_field = true 63 | 64 | # Parameter preferences 65 | dotnet_code_quality_unused_parameters = all 66 | 67 | # Suppression preferences 68 | dotnet_remove_unnecessary_suppression_exclusions = none 69 | 70 | #### C# Coding Conventions #### 71 | 72 | # var preferences 73 | csharp_style_var_elsewhere = false 74 | csharp_style_var_for_built_in_types = true:error 75 | csharp_style_var_when_type_is_apparent = true:error 76 | 77 | # Expression-bodied members 78 | csharp_style_expression_bodied_accessors = true 79 | csharp_style_expression_bodied_constructors = false 80 | csharp_style_expression_bodied_indexers = true 81 | csharp_style_expression_bodied_lambdas = true 82 | csharp_style_expression_bodied_local_functions = false 83 | csharp_style_expression_bodied_methods = false 84 | csharp_style_expression_bodied_operators = false 85 | csharp_style_expression_bodied_properties = true 86 | 87 | # Pattern matching preferences 88 | csharp_style_pattern_matching_over_as_with_null_check = true 89 | csharp_style_pattern_matching_over_is_with_cast_check = true 90 | csharp_style_prefer_not_pattern = true 91 | csharp_style_prefer_pattern_matching = true 92 | csharp_style_prefer_switch_expression = true 93 | 94 | # Null-checking preferences 95 | csharp_style_conditional_delegate_call = true 96 | 97 | # Modifier preferences 98 | csharp_prefer_static_local_function = true 99 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async 100 | 101 | # Code-block preferences 102 | csharp_prefer_braces = true 103 | csharp_prefer_simple_using_statement = true 104 | 105 | # Expression-level preferences 106 | csharp_prefer_simple_default_expression = true 107 | csharp_style_deconstructed_variable_declaration = true 108 | csharp_style_implicit_object_creation_when_type_is_apparent = true 109 | csharp_style_inlined_variable_declaration = true 110 | csharp_style_pattern_local_over_anonymous_function = true 111 | csharp_style_prefer_index_operator = true 112 | csharp_style_prefer_range_operator = true 113 | csharp_style_throw_expression = true 114 | csharp_style_unused_value_assignment_preference = discard_variable 115 | csharp_style_unused_value_expression_statement_preference = discard_variable 116 | 117 | # 'using' directive preferences 118 | csharp_using_directive_placement = outside_namespace 119 | 120 | #### C# Formatting Rules #### 121 | 122 | # New line preferences 123 | csharp_new_line_before_catch = true 124 | csharp_new_line_before_else = true 125 | csharp_new_line_before_finally = true 126 | csharp_new_line_before_members_in_anonymous_types = true 127 | csharp_new_line_before_members_in_object_initializers = true 128 | csharp_new_line_before_open_brace = all 129 | csharp_new_line_between_query_expression_clauses = true 130 | 131 | # Indentation preferences 132 | csharp_indent_block_contents = true 133 | csharp_indent_braces = false 134 | csharp_indent_case_contents = true 135 | csharp_indent_case_contents_when_block = true 136 | csharp_indent_labels = one_less_than_current 137 | csharp_indent_switch_labels = true 138 | 139 | # Space preferences 140 | csharp_space_after_cast = false 141 | csharp_space_after_colon_in_inheritance_clause = true 142 | csharp_space_after_comma = true 143 | csharp_space_after_dot = false 144 | csharp_space_after_keywords_in_control_flow_statements = true 145 | csharp_space_after_semicolon_in_for_statement = true 146 | csharp_space_around_binary_operators = before_and_after 147 | csharp_space_around_declaration_statements = false 148 | csharp_space_before_colon_in_inheritance_clause = true 149 | csharp_space_before_comma = false 150 | csharp_space_before_dot = false 151 | csharp_space_before_open_square_brackets = false 152 | csharp_space_before_semicolon_in_for_statement = false 153 | csharp_space_between_empty_square_brackets = false 154 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 155 | csharp_space_between_method_call_name_and_opening_parenthesis = false 156 | csharp_space_between_method_call_parameter_list_parentheses = false 157 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 158 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 159 | csharp_space_between_method_declaration_parameter_list_parentheses = false 160 | csharp_space_between_parentheses = false 161 | csharp_space_between_square_brackets = false 162 | 163 | # Wrapping preferences 164 | csharp_preserve_single_line_blocks = true 165 | csharp_preserve_single_line_statements = true 166 | 167 | #### Naming styles #### 168 | 169 | # Naming rules 170 | 171 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion 172 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 173 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 174 | 175 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 176 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 177 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 178 | 179 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 180 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 181 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 182 | 183 | # Symbol specifications 184 | 185 | dotnet_naming_symbols.interface.applicable_kinds = interface 186 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 187 | dotnet_naming_symbols.interface.required_modifiers = 188 | 189 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 190 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 191 | dotnet_naming_symbols.types.required_modifiers = 192 | 193 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 194 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 195 | dotnet_naming_symbols.non_field_members.required_modifiers = 196 | 197 | # Naming styles 198 | 199 | dotnet_naming_style.pascal_case.required_prefix = 200 | dotnet_naming_style.pascal_case.required_suffix = 201 | dotnet_naming_style.pascal_case.word_separator = 202 | dotnet_naming_style.pascal_case.capitalization = pascal_case 203 | 204 | dotnet_naming_style.begins_with_i.required_prefix = I 205 | dotnet_naming_style.begins_with_i.required_suffix = 206 | dotnet_naming_style.begins_with_i.word_separator = 207 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 208 | -------------------------------------------------------------------------------- /Helpers/Compositor.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Drawing; 23 | using System.Drawing.Drawing2D; 24 | using System.Drawing.Imaging; 25 | using MapAssist.Types; 26 | using MapAssist.Settings; 27 | 28 | namespace MapAssist.Helpers 29 | { 30 | public class Compositor 31 | { 32 | private readonly AreaData _areaData; 33 | private readonly Bitmap _background; 34 | public readonly Point CropOffset; 35 | private readonly IReadOnlyList _pointsOfInterest; 36 | private readonly Dictionary<(string, int), Font> _fontCache = new Dictionary<(string, int), Font>(); 37 | 38 | private readonly Dictionary<(Shape, int, Color), Bitmap> _iconCache = 39 | new Dictionary<(Shape, int, Color), Bitmap>(); 40 | 41 | public Compositor(AreaData areaData, IReadOnlyList pointOfInterest) 42 | { 43 | _areaData = areaData; 44 | _pointsOfInterest = pointOfInterest; 45 | (_background, CropOffset) = DrawBackground(areaData, pointOfInterest); 46 | } 47 | 48 | public Bitmap Compose(GameData gameData, bool scale = true) 49 | { 50 | if (gameData.Area != _areaData.Area) 51 | { 52 | throw new ApplicationException("Asked to compose an image for a different area." + 53 | $"Compositor area: {_areaData.Area}, Game data: {gameData.Area}"); 54 | } 55 | 56 | var image = (Bitmap)_background.Clone(); 57 | 58 | using (Graphics imageGraphics = Graphics.FromImage(image)) 59 | { 60 | imageGraphics.CompositingQuality = CompositingQuality.HighQuality; 61 | imageGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic; 62 | imageGraphics.SmoothingMode = SmoothingMode.HighQuality; 63 | imageGraphics.PixelOffsetMode = PixelOffsetMode.HighQuality; 64 | 65 | Point localPlayerPosition = gameData.PlayerPosition 66 | .OffsetFrom(_areaData.Origin) 67 | .OffsetFrom(CropOffset) 68 | .OffsetFrom(new Point(Settings.Rendering.Player.IconSize, Settings.Rendering.Player.IconSize)); 69 | 70 | if (Settings.Rendering.Player.CanDrawIcon()) 71 | { 72 | Bitmap playerIcon = GetIcon(Settings.Rendering.Player); 73 | imageGraphics.DrawImage(playerIcon, localPlayerPosition); 74 | } 75 | 76 | // The lines are dynamic, and follow the player, so have to be drawn here. 77 | // The rest can be done in DrawBackground. 78 | foreach (PointOfInterest poi in _pointsOfInterest) 79 | { 80 | if (poi.RenderingSettings.CanDrawLine()) 81 | { 82 | var pen = new Pen(poi.RenderingSettings.LineColor, poi.RenderingSettings.LineThickness); 83 | if (poi.RenderingSettings.CanDrawArrowHead()) 84 | { 85 | pen.CustomEndCap = new AdjustableArrowCap(poi.RenderingSettings.ArrowHeadSize, 86 | poi.RenderingSettings.ArrowHeadSize); 87 | } 88 | 89 | imageGraphics.DrawLine(pen, localPlayerPosition, 90 | poi.Position.OffsetFrom(_areaData.Origin).OffsetFrom(CropOffset)); 91 | } 92 | } 93 | MobRendering render = Utils.GetMobRendering(); 94 | foreach (var monster in GameMemory.Monsters) 95 | { 96 | var clr = monster.UniqueFlag == 0 ? render.NormalColor : render.UniqueColor; 97 | var pen = new Pen(clr, 1); 98 | var sz = new Size(5, 5); 99 | var sz2 = new Size(2, 2); 100 | var midPoint = monster.Position.OffsetFrom(_areaData.Origin).OffsetFrom(CropOffset); 101 | var rect = new Rectangle(midPoint, sz); 102 | imageGraphics.DrawRectangle(pen, rect); 103 | var i = 0; 104 | foreach(var immunity in monster.Immunities) 105 | { 106 | var brush = new SolidBrush(ResistColors.ResistColor[immunity]); 107 | var iPoint = new Point((i * -2) + (1 * (monster.Immunities.Count - 1)) - 1, 3); 108 | var pen2 = new Pen(ResistColors.ResistColor[immunity], 1); 109 | var rect2 = new Rectangle(midPoint.OffsetFrom(iPoint), sz2); 110 | imageGraphics.FillRectangle(brush, rect2); 111 | i++; 112 | } 113 | } 114 | } 115 | 116 | double multiplier = 1; 117 | 118 | if (scale) 119 | { 120 | double biggestDimension = Math.Max(image.Width, image.Height); 121 | 122 | multiplier = Settings.Map.Size / biggestDimension; 123 | 124 | if (multiplier == 0) 125 | { 126 | multiplier = 1; 127 | } 128 | } 129 | 130 | // ReSharper disable once CompareOfFloatsByEqualityOperator 131 | if (multiplier != 1) 132 | { 133 | image = ImageUtils.ResizeImage(image, (int)(image.Width * multiplier), 134 | (int)(image.Height * multiplier)); 135 | } 136 | 137 | // ReSharper disable once ConditionIsAlwaysTrueOrFalse 138 | if (scale && Settings.Map.Rotate) 139 | { 140 | image = ImageUtils.RotateImage(image, 53, true, false, Color.Transparent); 141 | } 142 | 143 | return image; 144 | } 145 | 146 | private (Bitmap, Point) DrawBackground(AreaData areaData, IReadOnlyList pointOfInterest) 147 | { 148 | var background = new Bitmap(areaData.CollisionGrid[0].Length, areaData.CollisionGrid.Length, 149 | PixelFormat.Format32bppArgb); 150 | using (Graphics backgroundGraphics = Graphics.FromImage(background)) 151 | { 152 | backgroundGraphics.FillRectangle(new SolidBrush(Color.Transparent), 0, 0, 153 | areaData.CollisionGrid[0].Length, 154 | areaData.CollisionGrid.Length); 155 | backgroundGraphics.CompositingQuality = CompositingQuality.HighQuality; 156 | backgroundGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic; 157 | backgroundGraphics.SmoothingMode = SmoothingMode.HighQuality; 158 | backgroundGraphics.PixelOffsetMode = PixelOffsetMode.HighQuality; 159 | 160 | for (var y = 0; y < areaData.CollisionGrid.Length; y++) 161 | { 162 | for (var x = 0; x < areaData.CollisionGrid[y].Length; x++) 163 | { 164 | int type = areaData.CollisionGrid[y][x]; 165 | Color? typeColor = Settings.Map.MapColors[type]; 166 | if (typeColor != null) 167 | { 168 | background.SetPixel(x, y, (Color)typeColor); 169 | } 170 | } 171 | } 172 | 173 | foreach (PointOfInterest poi in pointOfInterest) 174 | { 175 | if (poi.RenderingSettings.CanDrawIcon()) 176 | { 177 | Bitmap icon = GetIcon(poi.RenderingSettings); 178 | backgroundGraphics.DrawImage(icon, poi.Position.OffsetFrom(areaData.Origin)); 179 | } 180 | 181 | if (!string.IsNullOrWhiteSpace(poi.Label) && poi.RenderingSettings.CanDrawLabel()) 182 | { 183 | Font font = GetFont(poi.RenderingSettings); 184 | backgroundGraphics.DrawString(poi.Label, font, 185 | new SolidBrush(poi.RenderingSettings.LabelColor), 186 | poi.Position.OffsetFrom(areaData.Origin)); 187 | } 188 | } 189 | 190 | return ImageUtils.CropBitmap(background); 191 | } 192 | } 193 | 194 | public Font GetFont(string fontStr, int fontSize) 195 | { 196 | (string LabelFont, int LabelFontSize) cacheKey = (fontStr, fontSize); 197 | if (!_fontCache.ContainsKey(cacheKey)) 198 | { 199 | var font = new Font(fontStr, 200 | fontSize); 201 | _fontCache[cacheKey] = font; 202 | } 203 | 204 | return _fontCache[cacheKey]; 205 | } 206 | private Font GetFont(PointOfInterestRendering poiSettings) 207 | { 208 | (string LabelFont, int LabelFontSize) cacheKey = (poiSettings.LabelFont, poiSettings.LabelFontSize); 209 | if (!_fontCache.ContainsKey(cacheKey)) 210 | { 211 | var font = new Font(poiSettings.LabelFont, 212 | poiSettings.LabelFontSize); 213 | _fontCache[cacheKey] = font; 214 | } 215 | 216 | return _fontCache[cacheKey]; 217 | } 218 | 219 | private Bitmap GetIcon(PointOfInterestRendering poiSettings) 220 | { 221 | (Shape IconShape, int IconSize, Color Color) cacheKey = (poiSettings.IconShape, poiSettings.IconSize, Color: poiSettings.IconColor); 222 | if (!_iconCache.ContainsKey(cacheKey)) 223 | { 224 | var bitmap = new Bitmap(poiSettings.IconSize, poiSettings.IconSize, PixelFormat.Format32bppArgb); 225 | using (Graphics g = Graphics.FromImage(bitmap)) 226 | { 227 | g.SmoothingMode = SmoothingMode.AntiAlias; 228 | switch (poiSettings.IconShape) 229 | { 230 | case Shape.Ellipse: 231 | g.FillEllipse(new SolidBrush(poiSettings.IconColor), 0, 0, poiSettings.IconSize, 232 | poiSettings.IconSize); 233 | break; 234 | case Shape.Rectangle: 235 | g.FillRectangle(new SolidBrush(poiSettings.IconColor), 0, 0, poiSettings.IconSize, 236 | poiSettings.IconSize); 237 | break; 238 | } 239 | } 240 | 241 | _iconCache[cacheKey] = bitmap; 242 | } 243 | 244 | return _iconCache[cacheKey]; 245 | } 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /Types/Area.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System.Collections.Generic; 21 | 22 | namespace MapAssist.Types 23 | { 24 | public enum Area : uint 25 | { 26 | Abaddon = 125, 27 | AncientTunnels = 65, 28 | ArcaneSanctuary = 74, 29 | ArreatPlateau = 112, 30 | ArreatSummit = 120, 31 | Barracks = 28, 32 | BlackMarsh = 6, 33 | BloodMoor = 2, 34 | BloodyFoothills = 110, 35 | BurialGrounds = 17, 36 | CanyonOfTheMagi = 46, 37 | CatacombsLevel1 = 34, 38 | CatacombsLevel2 = 35, 39 | CatacombsLevel3 = 36, 40 | CatacombsLevel4 = 37, 41 | Cathedral = 33, 42 | CaveLevel1 = 9, 43 | CaveLevel2 = 13, 44 | ChaosSanctuary = 108, 45 | CityOfTheDamned = 106, 46 | ClawViperTempleLevel1 = 58, 47 | ClawViperTempleLevel2 = 61, 48 | ColdPlains = 3, 49 | Crypt = 18, 50 | CrystallinePassage = 113, 51 | DarkWood = 5, 52 | DenOfEvil = 8, 53 | DisusedFane = 95, 54 | DisusedReliquary = 99, 55 | DrifterCavern = 116, 56 | DryHills = 42, 57 | DuranceOfHateLevel1 = 100, 58 | DuranceOfHateLevel2 = 101, 59 | DuranceOfHateLevel3 = 102, 60 | DurielsLair = 73, 61 | FarOasis = 43, 62 | FlayerDungeonLevel1 = 88, 63 | FlayerDungeonLevel2 = 89, 64 | FlayerDungeonLevel3 = 91, 65 | FlayerJungle = 78, 66 | ForgottenReliquary = 96, 67 | ForgottenSands = 134, 68 | ForgottenTemple = 97, 69 | ForgottenTower = 20, 70 | FrigidHighlands = 111, 71 | FrozenRiver = 114, 72 | FrozenTundra = 117, 73 | FurnaceOfPain = 135, 74 | GlacialTrail = 115, 75 | GreatMarsh = 77, 76 | HallsOfAnguish = 122, 77 | HallsOfPain = 123, 78 | HallsOfTheDeadLevel1 = 56, 79 | HallsOfTheDeadLevel2 = 57, 80 | HallsOfTheDeadLevel3 = 60, 81 | HallsOfVaught = 124, 82 | HaremLevel1 = 50, 83 | HaremLevel2 = 51, 84 | Harrogath = 109, 85 | HoleLevel1 = 11, 86 | HoleLevel2 = 15, 87 | IcyCellar = 119, 88 | InfernalPit = 127, 89 | InnerCloister = 32, 90 | JailLevel1 = 29, 91 | JailLevel2 = 30, 92 | JailLevel3 = 31, 93 | KurastBazaar = 80, 94 | KurastCauseway = 82, 95 | KurastDocks = 75, 96 | LostCity = 44, 97 | LowerKurast = 79, 98 | LutGholein = 40, 99 | MaggotLairLevel1 = 62, 100 | MaggotLairLevel2 = 63, 101 | MaggotLairLevel3 = 64, 102 | MatronsDen = 133, 103 | Mausoleum = 19, 104 | MonasteryGate = 26, 105 | MooMooFarm = 39, 106 | NihlathaksTemple = 121, 107 | None = 0, 108 | OuterCloister = 27, 109 | OuterSteppes = 104, 110 | PalaceCellarLevel1 = 52, 111 | PalaceCellarLevel2 = 53, 112 | PalaceCellarLevel3 = 54, 113 | PitLevel1 = 12, 114 | PitLevel2 = 16, 115 | PitOfAcheron = 126, 116 | PlainsOfDespair = 105, 117 | RiverOfFlame = 107, 118 | RockyWaste = 41, 119 | RogueEncampment = 1, 120 | RuinedFane = 98, 121 | RuinedTemple = 94, 122 | SewersLevel1Act2 = 47, 123 | SewersLevel1Act3 = 92, 124 | SewersLevel2Act2 = 48, 125 | SewersLevel2Act3 = 93, 126 | SewersLevel3Act2 = 49, 127 | SpiderCave = 84, 128 | SpiderCavern = 85, 129 | SpiderForest = 76, 130 | StonyField = 4, 131 | StonyTombLevel1 = 55, 132 | StonyTombLevel2 = 59, 133 | SwampyPitLevel1 = 86, 134 | SwampyPitLevel2 = 87, 135 | SwampyPitLevel3 = 90, 136 | TalRashasTomb1 = 66, 137 | TalRashasTomb2 = 67, 138 | TalRashasTomb3 = 68, 139 | TalRashasTomb4 = 69, 140 | TalRashasTomb5 = 70, 141 | TalRashasTomb6 = 71, 142 | TalRashasTomb7 = 72, 143 | TamoeHighland = 7, 144 | TheAncientsWay = 118, 145 | ThePandemoniumFortress = 103, 146 | TheWorldstoneChamber = 132, 147 | TheWorldStoneKeepLevel1 = 128, 148 | TheWorldStoneKeepLevel2 = 129, 149 | TheWorldStoneKeepLevel3 = 130, 150 | ThroneOfDestruction = 131, 151 | TowerCellarLevel1 = 21, 152 | TowerCellarLevel2 = 22, 153 | TowerCellarLevel3 = 23, 154 | TowerCellarLevel4 = 24, 155 | TowerCellarLevel5 = 25, 156 | Travincal = 83, 157 | Tristram = 38, 158 | UberTristram = 136, 159 | UndergroundPassageLevel1 = 10, 160 | UndergroundPassageLevel2 = 14, 161 | UpperKurast = 81, 162 | ValleyOfSnakes = 45, 163 | MapsAncientTemple = 137, 164 | MapsDesecratedTemple = 138, 165 | MapsFrigidPlateau = 139, 166 | MapsInfernalTrial = 140, 167 | MapsRuinedCitadel = 141, 168 | } 169 | 170 | public static class AreaExtensions 171 | { 172 | private readonly static Dictionary _areaNames = new Dictionary() 173 | { 174 | { 0, "None" }, 175 | { 1, "Rogue Encampment" }, 176 | { 2, "Blood Moor" }, 177 | { 3, "Cold Plains" }, 178 | { 4, "Stony Field" }, 179 | { 5, "Dark Wood" }, 180 | { 6, "Black Marsh" }, 181 | { 7, "Tamoe Highland" }, 182 | { 8, "Den Of Evil" }, 183 | { 9, "Cave Level 1" }, 184 | { 10, "Underground Passage Level 1" }, 185 | { 11, "Hole Level 1" }, 186 | { 12, "Pit Level 1" }, 187 | { 13, "Cave Level 2" }, 188 | { 14, "Underground Passage Level 2" }, 189 | { 15, "Hole Level 2" }, 190 | { 16, "Pit Level 2" }, 191 | { 17, "Burial Grounds" }, 192 | { 18, "Crypt" }, 193 | { 19, "Mausoleum" }, 194 | { 20, "Forgotten Tower" }, 195 | { 21, "Tower Cellar Level 1" }, 196 | { 22, "Tower Cellar Level 2" }, 197 | { 23, "Tower Cellar Level 3" }, 198 | { 24, "Tower Cellar Level 4" }, 199 | { 25, "Tower Cellar Level 5" }, 200 | { 26, "Monastery Gate" }, 201 | { 27, "Outer Cloister" }, 202 | { 28, "Barracks" }, 203 | { 29, "Jail Level 1" }, 204 | { 30, "Jail Level 2" }, 205 | { 31, "Jail Level 3" }, 206 | { 32, "Inner Cloister" }, 207 | { 33, "Cathedral" }, 208 | { 34, "Catacombs Level 1" }, 209 | { 35, "Catacombs Level 2" }, 210 | { 36, "Catacombs Level 3" }, 211 | { 37, "Catacombs Level 4" }, 212 | { 38, "Tristram" }, 213 | { 39, "Moo Moo Farm" }, 214 | { 40, "Lut Gholein" }, 215 | { 41, "Rocky Waste" }, 216 | { 42, "Dry Hills" }, 217 | { 43, "Far Oasis" }, 218 | { 44, "Lost City" }, 219 | { 45, "Valley Of Snakes" }, 220 | { 46, "Canyon Of The Magi" }, 221 | { 47, "A2 Sewers Level 1" }, 222 | { 48, "A2 Sewers Level 2" }, 223 | { 49, "A2 Sewers Level 3" }, 224 | { 50, "Harem Level 1" }, 225 | { 51, "Harem Level 2" }, 226 | { 52, "Palace Cellar Level 1" }, 227 | { 53, "Palace Cellar Level 2" }, 228 | { 54, "Palace Cellar Level 3" }, 229 | { 55, "Stony Tomb Level 1" }, 230 | { 56, "Halls Of The Dead Level 1" }, 231 | { 57, "Halls Of The Dead Level 2" }, 232 | { 58, "Claw Viper Temple Level 1" }, 233 | { 59, "Stony Tomb Level 2" }, 234 | { 60, "Halls Of The Dead Level 3" }, 235 | { 61, "Claw Viper Temple Level 2" }, 236 | { 62, "Maggot Lair Level 1" }, 237 | { 63, "Maggot Lair Level 2" }, 238 | { 64, "Maggot Lair Level 3" }, 239 | { 65, "Ancient Tunnels" }, 240 | { 66, "Tal Rashas Tomb #1" }, 241 | { 67, "Tal Rashas Tomb #2" }, 242 | { 68, "Tal Rashas Tomb #3" }, 243 | { 69, "Tal Rashas Tomb #4" }, 244 | { 70, "Tal Rashas Tomb #5" }, 245 | { 71, "Tal Rashas Tomb #6" }, 246 | { 72, "Tal Rashas Tomb #7" }, 247 | { 73, "Duriels Lair" }, 248 | { 74, "Arcane Sanctuary" }, 249 | { 75, "Kurast Docktown" }, 250 | { 76, "Spider Forest" }, 251 | { 77, "Great Marsh" }, 252 | { 78, "Flayer Jungle" }, 253 | { 79, "Lower Kurast" }, 254 | { 80, "Kurast Bazaar" }, 255 | { 81, "Upper Kurast" }, 256 | { 82, "Kurast Causeway" }, 257 | { 83, "Travincal" }, 258 | { 84, "Spider Cave" }, 259 | { 85, "Spider Cavern" }, 260 | { 86, "Swampy Pit Level 1" }, 261 | { 87, "Swampy Pit Level 2" }, 262 | { 88, "Flayer Dungeon Level 1" }, 263 | { 89, "Flayer Dungeon Level 2" }, 264 | { 90, "Swampy Pit Level 3" }, 265 | { 91, "Flayer Dungeon Level 3" }, 266 | { 92, "A3 Sewers Level 1" }, 267 | { 93, "A3 Sewers Level 2" }, 268 | { 94, "Ruined Temple" }, 269 | { 95, "Disused Fane" }, 270 | { 96, "Forgotten Reliquary" }, 271 | { 97, "Forgotten Temple" }, 272 | { 98, "Ruined Fane" }, 273 | { 99, "Disused Reliquary" }, 274 | { 100, "Durance Of Hate Level 1" }, 275 | { 101, "Durance Of Hate Level 2" }, 276 | { 102, "Durance Of Hate Level 3" }, 277 | { 103, "The Pandemonium Fortress" }, 278 | { 104, "Outer Steppes" }, 279 | { 105, "Plains Of Despair" }, 280 | { 106, "City Of The Damned" }, 281 | { 107, "River Of Flame" }, 282 | { 108, "Chaos Sanctuary" }, 283 | { 109, "Harrogath" }, 284 | { 110, "Bloody Foothills" }, 285 | { 111, "Frigid Highlands" }, 286 | { 112, "Arreat Plateau" }, 287 | { 113, "Crystalline Passage" }, 288 | { 114, "Frozen River" }, 289 | { 115, "Glacial Trail" }, 290 | { 116, "Drifter Cavern" }, 291 | { 117, "Frozen Tundra" }, 292 | { 118, "Ancient\'s Way" }, 293 | { 119, "Icy Cellar" }, 294 | { 120, "Arreat Summit" }, 295 | { 121, "Nihlathaks Temple" }, 296 | { 122, "Halls Of Anguish" }, 297 | { 123, "Halls Of Pain" }, 298 | { 124, "Halls Of Vaught" }, 299 | { 125, "Abaddon" }, 300 | { 126, "Pit Of Acheron" }, 301 | { 127, "Infernal Pit" }, 302 | { 128, "The Worldstone Keep Level 1" }, 303 | { 129, "The Worldstone Keep Level 2" }, 304 | { 130, "The Worldstone Keep Level 3" }, 305 | { 131, "Throne Of Destruction" }, 306 | { 132, "The Worldstone Chamber" }, 307 | { 133, "Matron\'s Den" }, 308 | { 134, "Fogotten Sands" }, 309 | { 135, "Furnace of Pain" }, 310 | { 136, "Tristram" } 311 | }; 312 | 313 | public static string Name(this Area area) 314 | { 315 | return _areaNames.TryGetValue((int)area, out var areaName) ? areaName : area.ToString(); 316 | } 317 | 318 | public static bool IsValid(this Area area) 319 | { 320 | return (uint)area >= 1 && (uint)area <= 136; 321 | } 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /Overlay.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Drawing; 23 | using System.Windows.Forms; 24 | using MapAssist.Types; 25 | using MapAssist.Helpers; 26 | using MapAssist.Settings; 27 | using Gma.System.MouseKeyHook; 28 | using System.Numerics; 29 | using System.Configuration; 30 | using System.Diagnostics; 31 | 32 | namespace MapAssist 33 | { 34 | public partial class Overlay : Form 35 | { 36 | // Move to windows external 37 | private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); 38 | private const uint SWP_NOSIZE = 0x0001; 39 | private const uint SWP_NOMOVE = 0x0002; 40 | private const uint TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE; 41 | private readonly Timer _timer = new Timer(); 42 | private GameData _currentGameData; 43 | private Compositor _compositor; 44 | private AreaData _areaData; 45 | private MapApi _mapApi; 46 | private bool _show = true; 47 | private Screen _screen; 48 | 49 | public Overlay(IKeyboardMouseEvents keyboardMouseEvents) 50 | { 51 | InitializeComponent(); 52 | keyboardMouseEvents.KeyPress += (_, args) => 53 | { 54 | if (InGame()) 55 | { 56 | if (args.KeyChar == Map.ToggleKey) 57 | { 58 | _show = !_show; 59 | } 60 | if (args.KeyChar == Map.ZoomInKey) 61 | { 62 | if (Map.ZoomLevel > 0.25f) 63 | { 64 | Map.ZoomLevel -= 0.25f; 65 | Map.Size = (int)(Map.Size * 1.15f); 66 | } 67 | } 68 | if (args.KeyChar == Map.ZoomOutKey) 69 | { 70 | if (Map.ZoomLevel < 4f) 71 | { 72 | Map.ZoomLevel += 0.25f; 73 | Map.Size = (int)(Map.Size * .85f); 74 | } 75 | } 76 | } 77 | }; 78 | } 79 | 80 | private void Overlay_Load(object sender, EventArgs e) 81 | { 82 | Map.InitMapColors(); 83 | Rectangle screen = Screen.PrimaryScreen.WorkingArea; 84 | var width = Width >= screen.Width ? screen.Width : (screen.Width + Width) / 2; 85 | var height = Height >= screen.Height ? screen.Height : (screen.Height + Height) / 2; 86 | Location = new Point((screen.Width - width) / 2, (screen.Height - height) / 2); 87 | Size = new Size(width, height); 88 | Opacity = Map.Opacity; 89 | 90 | _timer.Interval = Map.UpdateTime; 91 | _timer.Tick += MapUpdateTimer_Tick; 92 | _timer.Start(); 93 | 94 | if (Map.AlwaysOnTop) SetTopMost(); 95 | 96 | mapOverlay.Location = new Point(0, 0); 97 | mapOverlay.Width = Width; 98 | mapOverlay.Height = Height; 99 | mapOverlay.BackColor = Color.Transparent; 100 | } 101 | 102 | private void Overlay_FormClosing(object sender, EventArgs e) 103 | { 104 | _mapApi?.Dispose(); 105 | } 106 | 107 | private void MapUpdateTimer_Tick(object sender, EventArgs e) 108 | { 109 | _timer.Stop(); 110 | 111 | GameData gameData = GameMemory.GetGameData(); 112 | if (gameData != null) 113 | { 114 | if (gameData.HasGameChanged(_currentGameData)) 115 | { 116 | Console.WriteLine($"Game changed: {gameData}"); 117 | _mapApi?.Dispose(); 118 | _mapApi = new MapApi(MapApi.Client, gameData.Difficulty, gameData.MapSeed); 119 | } 120 | 121 | if (gameData.HasMapChanged(_currentGameData)) 122 | { 123 | Debug.WriteLine($"Area changed: {gameData.Area}"); 124 | if (gameData.Area != Area.None) 125 | { 126 | _areaData = _mapApi.GetMapData(gameData.Area); 127 | List pointsOfInterest = PointOfInterestHandler.Get(_mapApi, _areaData); 128 | _compositor = new Compositor(_areaData, pointsOfInterest); 129 | } 130 | else 131 | { 132 | _compositor = null; 133 | } 134 | } 135 | } 136 | 137 | _currentGameData = gameData; 138 | 139 | if (ShouldHideMap()) 140 | { 141 | mapOverlay.Hide(); 142 | } 143 | else 144 | { 145 | if (!mapOverlay.Visible) 146 | { 147 | mapOverlay.Show(); 148 | if (Map.AlwaysOnTop) SetTopMost(); 149 | } 150 | mapOverlay.Refresh(); 151 | } 152 | 153 | _timer.Start(); 154 | } 155 | 156 | private void SetTopMost() 157 | { 158 | var initialStyle = (uint)WindowsExternal.GetWindowLongPtr(Handle, -20); 159 | WindowsExternal.SetWindowLong(Handle, -20, initialStyle | 0x80000 | 0x20); 160 | WindowsExternal.SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS); 161 | } 162 | 163 | private bool ShouldHideMap() 164 | { 165 | if (!_show) return true; 166 | if (!InGame()) return true; 167 | if (_currentGameData.Area == Area.None) return true; 168 | if (Array.Exists(Map.HiddenAreas, element => element == _currentGameData.Area)) return true; 169 | if (Map.ToggleViaInGameMap && !_currentGameData.MapShown) return true; 170 | return false; 171 | } 172 | 173 | private bool InGame() 174 | { 175 | return _currentGameData != null && _currentGameData.MainWindowHandle != IntPtr.Zero && 176 | WindowsExternal.GetForegroundWindow() == _currentGameData.MainWindowHandle; 177 | } 178 | 179 | private void MapOverlay_Paint(object sender, PaintEventArgs e) 180 | { 181 | if (_compositor == null) 182 | { 183 | return; 184 | } 185 | 186 | UpdateLocation(); 187 | 188 | Bitmap gameMap = _compositor.Compose(_currentGameData, !Map.OverlayMode); 189 | 190 | var msgCount = 0; 191 | foreach (var warning in GameMemory.WarningMessages) 192 | { 193 | var fontSize = Map.WarnImmuneNPCFontSize; 194 | Font font = _compositor.GetFont(Map.WarnImmuneNPCFont, fontSize); 195 | var stringFormat = new StringFormat(); 196 | stringFormat.Alignment = Map.WarnNPCHorizontalAlign; 197 | stringFormat.LineAlignment = Map.WarnNPCVerticalAlign; 198 | e.Graphics.DrawString(warning, font, 199 | new SolidBrush(Map.WarnNPCFontColor), 200 | new Point(Screen.PrimaryScreen.WorkingArea.Width / 2, 10 + (msgCount * (fontSize + fontSize / 2))), stringFormat); 201 | msgCount++; 202 | } 203 | if (Map.OverlayMode) 204 | { 205 | float w = 0; 206 | float h = 0; 207 | var scale = 0.0F; 208 | var center = new Vector2(); 209 | 210 | if (ConfigurationManager.AppSettings["ZoomLevelDefault"] == null) { Map.ZoomLevel = 1; } 211 | 212 | switch (Map.Position) 213 | { 214 | case MapPosition.Center: 215 | w = _screen.WorkingArea.Width; 216 | h = _screen.WorkingArea.Height; 217 | scale = (1024.0F / h * w * 3f / 4f / 2.3F) * Map.ZoomLevel; 218 | center = new Vector2(w / 2, h / 2 + 20); 219 | 220 | e.Graphics.SetClip(new RectangleF(0, 0, w, h)); 221 | break; 222 | case MapPosition.TopLeft: 223 | w = 640; 224 | h = 360; 225 | scale = (1024.0F / h * w * 3f / 4f / 3.35F) * Map.ZoomLevel; 226 | center = new Vector2(w / 2, (h / 2) + 48); 227 | 228 | e.Graphics.SetClip(new RectangleF(0, 50, w, h)); 229 | break; 230 | case MapPosition.TopRight: 231 | w = 640; 232 | h = 360; 233 | scale = (1024.0F / h * w * 3f / 4f / 3.35F) * Map.ZoomLevel; 234 | center = new Vector2(w / 2, (h / 2) + 40); 235 | 236 | e.Graphics.TranslateTransform(_screen.WorkingArea.Width - w, -8); 237 | e.Graphics.SetClip(new RectangleF(0, 50, w, h)); 238 | break; 239 | } 240 | 241 | Point playerPosInArea = _currentGameData.PlayerPosition.OffsetFrom(_areaData.Origin).OffsetFrom(_compositor.CropOffset); 242 | 243 | var playerPos = new Vector2(playerPosInArea.X, playerPosInArea.Y); 244 | Vector2 Transform(Vector2 p) => 245 | center + 246 | DeltaInWorldToMinimapDelta( 247 | p - playerPos, 248 | (float)Math.Sqrt(w * w + h * h), 249 | scale, 250 | 0); 251 | 252 | var p1 = Transform(new Vector2(0, 0)); 253 | var p2 = Transform(new Vector2(gameMap.Width, 0)); 254 | var p4 = Transform(new Vector2(0, gameMap.Height)); 255 | 256 | PointF[] destinationPoints = { 257 | new PointF(p1.X, p1.Y), 258 | new PointF(p2.X, p2.Y), 259 | new PointF(p4.X, p4.Y) 260 | }; 261 | 262 | e.Graphics.DrawImage(gameMap, destinationPoints); 263 | } 264 | else 265 | { 266 | var anchor = new Point(0, 0); 267 | switch (Map.Position) 268 | { 269 | case MapPosition.Center: 270 | anchor = new Point(_screen.WorkingArea.Width / 2, _screen.WorkingArea.Height / 2); 271 | break; 272 | case MapPosition.TopRight: 273 | anchor = new Point(_screen.WorkingArea.Width - gameMap.Width, 0); 274 | break; 275 | case MapPosition.TopLeft: 276 | anchor = new Point(0, 0); 277 | break; 278 | } 279 | 280 | e.Graphics.DrawImage(gameMap, anchor); 281 | } 282 | } 283 | 284 | public Vector2 DeltaInWorldToMinimapDelta(Vector2 delta, double diag, float scale, float deltaZ = 0) 285 | { 286 | var CAMERA_ANGLE = -26F * 3.14159274F / 180; 287 | 288 | var cos = (float)(diag * Math.Cos(CAMERA_ANGLE) / scale); 289 | var sin = (float)(diag * Math.Sin(CAMERA_ANGLE) / 290 | scale); 291 | 292 | return new Vector2((delta.X - delta.Y) * cos, deltaZ - (delta.X + delta.Y) * sin); 293 | } 294 | 295 | /// 296 | /// Update the location and size of the form relative to the window location. 297 | /// 298 | private void UpdateLocation() 299 | { 300 | _screen = Screen.FromHandle(_currentGameData.MainWindowHandle); 301 | Location = new Point(_screen.WorkingArea.X, _screen.WorkingArea.Y); 302 | Size = new Size(_screen.WorkingArea.Width, _screen.WorkingArea.Height); 303 | mapOverlay.Size = Size; 304 | } 305 | } 306 | } 307 | -------------------------------------------------------------------------------- /Types/Stats.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | using System.Collections.Generic; 20 | using System.Drawing; 21 | 22 | namespace MapAssist.Types 23 | { 24 | public static class ResistColors 25 | { 26 | public static Dictionary ResistColor = new Dictionary 27 | { 28 | { Resist.PHYSICAL, Color.Peru }, 29 | { Resist.MAGIC, Color.OrangeRed }, 30 | { Resist.FIRE, Color.Red }, 31 | { Resist.LIGHTNING, Color.Yellow }, 32 | { Resist.COLD, Color.CornflowerBlue }, 33 | { Resist.POISON, Color.LimeGreen }, 34 | 35 | }; 36 | } 37 | public enum Resist 38 | { 39 | PHYSICAL = 0, 40 | MAGIC = 1, 41 | FIRE = 2, 42 | LIGHTNING = 3, 43 | COLD = 4, 44 | POISON = 5 45 | } 46 | public enum Stat : short 47 | { 48 | STAT_INVALID = -1, 49 | STAT_STRENGTH = 0, // 000 50 | STAT_ENERGY, // 001 51 | STAT_DEXTERITY, // 002 52 | STAT_VITALITY, // 003 53 | STAT_STATPTS, // 004 54 | STAT_SKILLPTS, // 005 55 | STAT_HITPOINTS, // 006 56 | STAT_MAXHP, // 007 57 | STAT_MANA, // 008 58 | STAT_MAXMANA, // 009 59 | STAT_STAMINA, // 00A 60 | STAT_MAXSTAMINA, // 00B 61 | STAT_LEVEL, // 00C 62 | STAT_EXPERIENCE, // 00D 63 | STAT_GOLD, // 00E 64 | STAT_GOLDBANK, // 00F 65 | STAT_ITEM_ARMOR_PERCENT, // 010 66 | STAT_ITEM_MAXDAMAGE_PERCENT, // 011 67 | STAT_ITEM_MINDAMAGE_PERCENT, // 012 68 | STAT_TOHIT, 69 | STAT_TOBLOCK, 70 | STAT_MINDAMAGE, 71 | STAT_MAXDAMAGE, 72 | STAT_SECONDARY_MINDAMAGE, 73 | STAT_SECONDARY_MAXDAMAGE, 74 | STAT_DAMAGEPERCENT, 75 | STAT_MANARECOVERY, 76 | STAT_MANARECOVERYBONUS, 77 | STAT_STAMINARECOVERYBONUS, 78 | STAT_LASTEXP, 79 | STAT_NEXTEXP, 80 | STAT_ARMORCLASS, 81 | STAT_ARMORCLASS_VS_MISSILE, 82 | STAT_ARMORCLASS_VS_HTH, 83 | STAT_NORMAL_DAMAGE_REDUCTION, 84 | STAT_MAGIC_DAMAGE_REDUCTION, 85 | STAT_DAMAGERESIST, 86 | STAT_MAGICRESIST, 87 | STAT_MAXMAGICRESIST, 88 | STAT_FIRERESIST, 89 | STAT_MAXFIRERESIST, 90 | STAT_LIGHTRESIST, 91 | STAT_MAXLIGHTRESIST, 92 | STAT_COLDRESIST, 93 | STAT_MAXCOLDRESIST, 94 | STAT_POISONRESIST, 95 | STAT_MAXPOISONRESIST, 96 | STAT_DAMAGEAURA, 97 | STAT_FIREMINDAM, 98 | STAT_FIREMAXDAM, 99 | STAT_LIGHTMINDAM, 100 | STAT_LIGHTMAXDAM, 101 | STAT_MAGICMINDAM, 102 | STAT_MAGICMAXDAM, 103 | STAT_COLDMINDAM, 104 | STAT_COLDMAXDAM, 105 | STAT_COLDLENGTH, 106 | STAT_POISONMINDAM, 107 | STAT_POISONMAXDAM, 108 | STAT_POISONLENGTH, 109 | STAT_LIFEDRAINMINDAM, 110 | STAT_LIFEDRAINMAXDAM, 111 | STAT_MANADRAINMINDAM, 112 | STAT_MANADRAINMAXDAM, 113 | STAT_STAMDRAINMINDAM, 114 | STAT_STAMDRAINMAXDAM, 115 | STAT_STUNLENGTH, 116 | STAT_VELOCITYPERCENT, 117 | STAT_ATTACKRATE, 118 | STAT_OTHER_ANIMRATE, 119 | STAT_QUANTITY, 120 | STAT_VALUE, 121 | STAT_DURABILITY, 122 | STAT_MAXDURABILITY, 123 | STAT_HPREGEN, 124 | STAT_ITEM_MAXDURABILITY_PERCENT, 125 | STAT_ITEM_MAXHP_PERCENT, 126 | STAT_ITEM_MAXMANA_PERCENT, 127 | STAT_ITEM_ATTACKERTAKESDAMAGE, 128 | STAT_ITEM_GOLDBONUS, 129 | STAT_ITEM_MAGICBONUS, 130 | STAT_ITEM_KNOCKBACK, 131 | STAT_ITEM_TIMEDURATION, 132 | STAT_ITEM_ADDCLASSSKILLS, 133 | STAT_UNSENTPARAM1, 134 | STAT_ITEM_ADDEXPERIENCE, 135 | STAT_ITEM_HEALAFTERKILL, 136 | STAT_ITEM_REDUCEDPRICES, 137 | STAT_ITEM_DOUBLEHERBDURATION, 138 | STAT_ITEM_LIGHTRADIUS, 139 | STAT_ITEM_LIGHTCOLOR, 140 | STAT_ITEM_REQ_PERCENT, 141 | STAT_ITEM_LEVELREQ, 142 | STAT_ITEM_FASTERATTACKRATE, 143 | STAT_ITEM_LEVELREQPCT, 144 | STAT_LASTBLOCKFRAME, 145 | STAT_ITEM_FASTERMOVEVELOCITY, 146 | STAT_ITEM_NONCLASSSKILL, 147 | STAT_STATE, 148 | STAT_ITEM_FASTERGETHITRATE, 149 | STAT_MONSTER_PLAYERCOUNT, 150 | STAT_SKILL_POISON_OVERRIDE_LENGTH, 151 | STAT_ITEM_FASTERBLOCKRATE, 152 | STAT_SKILL_BYPASS_UNDEAD, 153 | STAT_SKILL_BYPASS_DEMONS, 154 | STAT_ITEM_FASTERCASTRATE, 155 | STAT_SKILL_BYPASS_BEASTS, 156 | STAT_ITEM_SINGLESKILL, 157 | STAT_ITEM_RESTINPEACE, 158 | STAT_CURSE_RESISTANCE, 159 | STAT_ITEM_POISONLENGTHRESIST, 160 | STAT_ITEM_NORMALDAMAGE, 161 | STAT_ITEM_HOWL, 162 | STAT_ITEM_STUPIDITY, 163 | STAT_ITEM_DAMAGETOMANA, 164 | STAT_ITEM_IGNORETARGETAC, 165 | STAT_ITEM_FRACTIONALTARGETAC, 166 | STAT_ITEM_PREVENTHEAL, 167 | STAT_ITEM_HALFFREEZEDURATION, 168 | STAT_ITEM_TOHIT_PERCENT, 169 | STAT_ITEM_DAMAGETARGETAC, 170 | STAT_ITEM_DEMONDAMAGE_PERCENT, 171 | STAT_ITEM_UNDEADDAMAGE_PERCENT, 172 | STAT_ITEM_DEMON_TOHIT, 173 | STAT_ITEM_UNDEAD_TOHIT, 174 | STAT_ITEM_THROWABLE, 175 | STAT_ITEM_ELEMSKILL, 176 | STAT_ITEM_ALLSKILLS, 177 | STAT_ITEM_ATTACKERTAKESLIGHTDAMAGE, 178 | STAT_IRONMAIDEN_LEVEL, 179 | STAT_LIFETAP_LEVEL, 180 | STAT_THORNS_PERCENT, 181 | STAT_BONEARMOR, 182 | STAT_BONEARMORMAX, 183 | STAT_ITEM_FREEZE, 184 | STAT_ITEM_OPENWOUNDS, 185 | STAT_ITEM_CRUSHINGBLOW, 186 | STAT_ITEM_KICKDAMAGE, 187 | STAT_ITEM_MANAAFTERKILL, 188 | STAT_ITEM_HEALAFTERDEMONKILL, 189 | STAT_ITEM_EXTRABLOOD, 190 | STAT_ITEM_DEADLYSTRIKE, 191 | STAT_ITEM_ABSORBFIRE_PERCENT, 192 | STAT_ITEM_ABSORBFIRE, 193 | STAT_ITEM_ABSORBLIGHT_PERCENT, 194 | STAT_ITEM_ABSORBLIGHT, 195 | STAT_ITEM_ABSORBMAGIC_PERCENT, 196 | STAT_ITEM_ABSORBMAGIC, 197 | STAT_ITEM_ABSORBCOLD_PERCENT, 198 | STAT_ITEM_ABSORBCOLD, 199 | STAT_ITEM_SLOW, 200 | STAT_ITEM_AURA, 201 | STAT_ITEM_INDESCTRUCTIBLE, 202 | STAT_ITEM_CANNOTBEFROZEN, 203 | STAT_ITEM_STAMINADRAINPCT, 204 | STAT_ITEM_REANIMATE, 205 | STAT_ITEM_PIERCE, 206 | STAT_ITEM_MAGICARROW, 207 | STAT_ITEM_EXPLOSIVEARROW, 208 | STAT_ITEM_THROW_MINDAMAGE, 209 | STAT_ITEM_THROW_MAXDAMAGE, 210 | STAT_SKILL_HANDOFATHENA, 211 | STAT_SKILL_STAMINAPERCENT, 212 | STAT_SKILL_PASSIVE_STAMINAPERCENT, 213 | STAT_SKILL_CONCENTRATION, 214 | STAT_SKILL_ENCHANT, 215 | STAT_SKILL_PIERCE, 216 | STAT_SKILL_CONVICTION, 217 | STAT_SKILL_CHILLINGARMOR, 218 | STAT_SKILL_FRENZY, 219 | STAT_SKILL_DECREPIFY, 220 | STAT_SKILL_ARMOR_PERCENT, 221 | STAT_ALIGNMENT, 222 | STAT_TARGET0, 223 | STAT_TARGET1, 224 | STAT_GOLDLOST, 225 | STAT_CONVERSION_LEVEL, 226 | STAT_CONVERSION_MAXHP, 227 | STAT_UNIT_DOOVERLAY, 228 | STAT_ATTACK_VS_MONTYPE, 229 | STAT_DAMAGE_VS_MONTYPE, 230 | STAT_FADE, 231 | STAT_ARMOR_OVERRIDE_PERCENT, 232 | STAT_UNUSED183, 233 | STAT_UNUSED184, 234 | STAT_UNUSED185, 235 | STAT_UNUSED186, 236 | STAT_UNUSED187, 237 | STAT_ITEM_ADDSKILL_TAB, 238 | STAT_UNUSED189, 239 | STAT_UNUSED190, 240 | STAT_UNUSED191, 241 | STAT_UNUSED192, 242 | STAT_UNUSED193, 243 | STAT_ITEM_NUMSOCKETS, 244 | STAT_ITEM_SKILLONATTACK, 245 | STAT_ITEM_SKILLONKILL, 246 | STAT_ITEM_SKILLONDEATH, 247 | STAT_ITEM_SKILLONHIT, 248 | STAT_ITEM_SKILLONLEVELUP, 249 | STAT_UNUSED200, 250 | STAT_ITEM_SKILLONGETHIT, 251 | STAT_UNUSED202, 252 | STAT_UNUSED203, 253 | STAT_ITEM_CHARGED_SKILL, 254 | STAT_UNUSED204, 255 | STAT_UNUSED205, 256 | STAT_UNUSED206, 257 | STAT_UNUSED207, 258 | STAT_UNUSED208, 259 | STAT_UNUSED209, 260 | STAT_UNUSED210, 261 | STAT_UNUSED211, 262 | STAT_UNUSED212, 263 | STAT_ITEM_ARMOR_PERLEVEL, 264 | STAT_ITEM_ARMORPERCENT_PERLEVEL, 265 | STAT_ITEM_HP_PERLEVEL, 266 | STAT_ITEM_MANA_PERLEVEL, 267 | STAT_ITEM_MAXDAMAGE_PERLEVEL, 268 | STAT_ITEM_MAXDAMAGE_PERCENT_PERLEVEL, 269 | STAT_ITEM_STRENGTH_PERLEVEL, 270 | STAT_ITEM_DEXTERITY_PERLEVEL, 271 | STAT_ITEM_ENERGY_PERLEVEL, 272 | STAT_ITEM_VITALITY_PERLEVEL, 273 | STAT_ITEM_TOHIT_PERLEVEL, 274 | STAT_ITEM_TOHITPERCENT_PERLEVEL, 275 | STAT_ITEM_COLD_DAMAGEMAX_PERLEVEL, 276 | STAT_ITEM_FIRE_DAMAGEMAX_PERLEVEL, 277 | STAT_ITEM_LTNG_DAMAGEMAX_PERLEVEL, 278 | STAT_ITEM_POIS_DAMAGEMAX_PERLEVEL, 279 | STAT_ITEM_RESIST_COLD_PERLEVEL, 280 | STAT_ITEM_RESIST_FIRE_PERLEVEL, 281 | STAT_ITEM_RESIST_LTNG_PERLEVEL, 282 | STAT_ITEM_RESIST_POIS_PERLEVEL, 283 | STAT_ITEM_ABSORB_COLD_PERLEVEL, 284 | STAT_ITEM_ABSORB_FIRE_PERLEVEL, 285 | STAT_ITEM_ABSORB_LTNG_PERLEVEL, 286 | STAT_ITEM_ABSORB_POIS_PERLEVEL, 287 | STAT_ITEM_THORNS_PERLEVEL, 288 | STAT_ITEM_FIND_GOLD_PERLEVEL, 289 | STAT_ITEM_FIND_MAGIC_PERLEVEL, 290 | STAT_ITEM_REGENSTAMINA_PERLEVEL, 291 | STAT_ITEM_STAMINA_PERLEVEL, 292 | STAT_ITEM_DAMAGE_DEMON_PERLEVEL, 293 | STAT_ITEM_DAMAGE_UNDEAD_PERLEVEL, 294 | STAT_ITEM_TOHIT_DEMON_PERLEVEL, 295 | STAT_ITEM_TOHIT_UNDEAD_PERLEVEL, 296 | STAT_ITEM_CRUSHINGBLOW_PERLEVEL, 297 | STAT_ITEM_OPENWOUNDS_PERLEVEL, 298 | STAT_ITEM_KICK_DAMAGE_PERLEVEL, 299 | STAT_ITEM_DEADLYSTRIKE_PERLEVEL, 300 | STAT_ITEM_FIND_GEMS_PERLEVEL, 301 | STAT_ITEM_REPLENISH_DURABILITY, 302 | STAT_ITEM_REPLENISH_QUANTITY, 303 | STAT_ITEM_EXTRA_STACK, 304 | STAT_ITEM_FIND_ITEM, 305 | STAT_ITEM_SLASH_DAMAGE, 306 | STAT_ITEM_SLASH_DAMAGE_PERCENT, 307 | STAT_ITEM_CRUSH_DAMAGE, 308 | STAT_ITEM_CRUSH_DAMAGE_PERCENT, 309 | STAT_ITEM_THRUST_DAMAGE, 310 | STAT_ITEM_THRUST_DAMAGE_PERCENT, 311 | STAT_ITEM_ABSORB_SLASH, 312 | STAT_ITEM_ABSORB_CRUSH, 313 | STAT_ITEM_ABSORB_THRUST, 314 | STAT_ITEM_ABSORB_SLASH_PERCENT, 315 | STAT_ITEM_ABSORB_CRUSH_PERCENT, 316 | STAT_ITEM_ABSORB_THRUST_PERCENT, 317 | STAT_ITEM_ARMOR_BYTIME, 318 | STAT_ITEM_ARMORPERCENT_BYTIME, 319 | STAT_ITEM_HP_BYTIME, 320 | STAT_ITEM_MANA_BYTIME, 321 | STAT_ITEM_MAXDAMAGE_BYTIME, 322 | STAT_ITEM_MAXDAMAGE_PERCENT_BYTIME, 323 | STAT_ITEM_STRENGTH_BYTIME, 324 | STAT_ITEM_DEXTERITY_BYTIME, 325 | STAT_ITEM_ENERGY_BYTIME, 326 | STAT_ITEM_VITALITY_BYTIME, 327 | STAT_ITEM_TOHIT_BYTIME, 328 | STAT_ITEM_TOHITPERCENT_BYTIME, 329 | STAT_ITEM_COLD_DAMAGEMAX_BYTIME, 330 | STAT_ITEM_FIRE_DAMAGEMAX_BYTIME, 331 | STAT_ITEM_LTNG_DAMAGEMAX_BYTIME, 332 | STAT_ITEM_POIS_DAMAGEMAX_BYTIME, 333 | STAT_ITEM_RESIST_COLD_BYTIME, 334 | STAT_ITEM_RESIST_FIRE_BYTIME, 335 | STAT_ITEM_RESIST_LTNG_BYTIME, 336 | STAT_ITEM_RESIST_POIS_BYTIME, 337 | STAT_ITEM_ABSORB_COLD_BYTIME, 338 | STAT_ITEM_ABSORB_FIRE_BYTIME, 339 | STAT_ITEM_ABSORB_LTNG_BYTIME, 340 | STAT_ITEM_ABSORB_POIS_BYTIME, 341 | STAT_ITEM_FIND_GOLD_BYTIME, 342 | STAT_ITEM_FIND_MAGIC_BYTIME, 343 | STAT_ITEM_REGENSTAMINA_BYTIME, 344 | STAT_ITEM_STAMINA_BYTIME, 345 | STAT_ITEM_DAMAGE_DEMON_BYTIME, 346 | STAT_ITEM_DAMAGE_UNDEAD_BYTIME, 347 | STAT_ITEM_TOHIT_DEMON_BYTIME, 348 | STAT_ITEM_TOHIT_UNDEAD_BYTIME, 349 | STAT_ITEM_CRUSHINGBLOW_BYTIME, 350 | STAT_ITEM_OPENWOUNDS_BYTIME, 351 | STAT_ITEM_KICK_DAMAGE_BYTIME, 352 | STAT_ITEM_DEADLYSTRIKE_BYTIME, 353 | STAT_ITEM_FIND_GEMS_BYTIME, 354 | STAT_ITEM_PIERCE_COLD, 355 | STAT_ITEM_PIERCE_FIRE, 356 | STAT_ITEM_PIERCE_LTNG, 357 | STAT_ITEM_PIERCE_POIS, 358 | STAT_ITEM_DAMAGE_VS_MONSTER, 359 | STAT_ITEM_DAMAGE_PERCENT_VS_MONSTER, 360 | STAT_ITEM_TOHIT_VS_MONSTER, 361 | STAT_ITEM_TOHIT_PERCENT_VS_MONSTER, 362 | STAT_ITEM_AC_VS_MONSTER, 363 | STAT_ITEM_AC_PERCENT_VS_MONSTER, 364 | STAT_FIRELENGTH, 365 | STAT_BURNINGMIN, 366 | STAT_BURNINGMAX, 367 | STAT_PROGRESSIVE_DAMAGE, 368 | STAT_PROGRESSIVE_STEAL, 369 | STAT_PROGRESSIVE_OTHER, 370 | STAT_PROGRESSIVE_FIRE, 371 | STAT_PROGRESSIVE_COLD, 372 | STAT_PROGRESSIVE_LIGHTNING, 373 | STAT_ITEM_EXTRA_CHARGES, 374 | STAT_PROGRESSIVE_TOHIT, 375 | STAT_POISON_COUNT, 376 | STAT_DAMAGE_FRAMERATE, 377 | STAT_PIERCE_IDX, 378 | STAT_PASSIVE_FIRE_MASTERY, 379 | STAT_PASSIVE_LTNG_MASTERY, 380 | STAT_PASSIVE_COLD_MASTERY, 381 | STAT_PASSIVE_POIS_MASTERY, 382 | STAT_PASSIVE_FIRE_PIERCE, 383 | STAT_PASSIVE_LTNG_PIERCE, 384 | STAT_PASSIVE_COLD_PIERCE, 385 | STAT_PASSIVE_POIS_PIERCE, 386 | STAT_PASSIVE_CRITICAL_STRIKE, 387 | STAT_PASSIVE_DODGE, 388 | STAT_PASSIVE_AVOID, 389 | STAT_PASSIVE_EVADE, 390 | STAT_PASSIVE_WARMTH, 391 | STAT_PASSIVE_MASTERY_MELEE_TH, 392 | STAT_PASSIVE_MASTERY_MELEE_DMG, 393 | STAT_PASSIVE_MASTERY_MELEE_CRIT, 394 | STAT_PASSIVE_MASTERY_THROW_TH, 395 | STAT_PASSIVE_MASTERY_THROW_DMG, 396 | STAT_PASSIVE_MASTERY_THROW_CRIT, 397 | STAT_PASSIVE_WEAPONBLOCK, 398 | STAT_PASSIVE_SUMMON_RESIST, 399 | STAT_MODIFIERLIST_SKILL, 400 | STAT_MODIFIERLIST_LEVEL, 401 | STAT_LAST_SENT_HP_PCT, 402 | STAT_SOURCE_UNIT_TYPE, 403 | STAT_SOURCE_UNIT_ID, 404 | STAT_SHORTPARAM1, 405 | STAT_QUESTITEMDIFFICULTY, 406 | STAT_PASSIVE_MAG_MASTERY, 407 | STAT_PASSIVE_MAG_PIERCE, 408 | }; 409 | } 410 | -------------------------------------------------------------------------------- /Helpers/GameMemory.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | using System; 21 | using System.Diagnostics; 22 | using System.Drawing; 23 | using System.Linq; 24 | using System.Runtime.InteropServices; 25 | using System.Text; 26 | using System.Collections.Generic; 27 | 28 | using MapAssist.Structs; 29 | using MapAssist.Types; 30 | using MapAssist.Settings; 31 | 32 | namespace MapAssist.Helpers 33 | { 34 | class GameMemory 35 | { 36 | private static readonly string ProcessName = Encoding.UTF8.GetString(new byte[] { 68, 50, 82 }); 37 | private static IntPtr PlayerUnitPtr; 38 | private static UnitAny PlayerUnit = default; 39 | private static int _lastProcessId = 0; 40 | public static List Monsters = new List(); 41 | public static List WarningMessages = new List(); 42 | private static Difficulty currentDifficulty = Difficulty.None; 43 | private static uint currentMapSeed = 0; 44 | 45 | unsafe public static GameData GetGameData() 46 | { 47 | IntPtr processHandle = IntPtr.Zero; 48 | 49 | try 50 | { 51 | Process[] process = Process.GetProcessesByName(ProcessName); 52 | 53 | Process gameProcess = null; 54 | 55 | IntPtr windowInFocus = WindowsExternal.GetForegroundWindow(); 56 | if (windowInFocus == IntPtr.Zero) 57 | { 58 | gameProcess = process.FirstOrDefault(); 59 | } 60 | else 61 | { 62 | gameProcess = process.FirstOrDefault(p => p.MainWindowHandle == windowInFocus); 63 | } 64 | 65 | if (gameProcess == null) 66 | { 67 | throw new Exception("Game process not found."); 68 | } 69 | 70 | // If changing processes we need to re-find the player 71 | if (gameProcess.Id != _lastProcessId) 72 | { 73 | ResetPlayerUnit(); 74 | } 75 | 76 | _lastProcessId = gameProcess.Id; 77 | 78 | processHandle = 79 | WindowsExternal.OpenProcess((uint)WindowsExternal.ProcessAccessFlags.VirtualMemoryRead, false, gameProcess.Id); 80 | IntPtr processAddress = gameProcess.MainModule.BaseAddress; 81 | if (PlayerUnitPtr == IntPtr.Zero) 82 | { 83 | var expansionCharacter = Read(processHandle, IntPtr.Add(processAddress, Offsets.ExpansionCheck)) == 1; 84 | var userBaseOffset = 0x30; 85 | var checkUser1 = 1; 86 | if (expansionCharacter) 87 | { 88 | userBaseOffset = 0x70; 89 | checkUser1 = 0; 90 | } 91 | var unitHashTable = Read(processHandle, IntPtr.Add(processAddress, Offsets.UnitHashTable)); 92 | foreach (var pUnitAny in unitHashTable.UnitTable) 93 | { 94 | var pListNext = pUnitAny; 95 | 96 | while (pListNext != IntPtr.Zero) 97 | { 98 | var unitAny = Read(processHandle, pListNext); 99 | if (unitAny.Inventory != IntPtr.Zero) 100 | { 101 | var UserBaseCheck = Read(processHandle, IntPtr.Add(unitAny.Inventory, userBaseOffset)); 102 | if (UserBaseCheck != checkUser1) 103 | { 104 | PlayerUnitPtr = pUnitAny; 105 | PlayerUnit = unitAny; 106 | break; 107 | } 108 | } 109 | pListNext = (IntPtr)unitAny.pListNext; 110 | } 111 | 112 | if (PlayerUnitPtr != IntPtr.Zero) 113 | { 114 | break; 115 | } 116 | } 117 | } 118 | 119 | if (PlayerUnitPtr == IntPtr.Zero) 120 | { 121 | currentDifficulty = Difficulty.None; 122 | currentMapSeed = 0; 123 | throw new Exception("Player pointer is zero."); 124 | } 125 | 126 | /*IntPtr aPlayerUnit = Read(processHandle, PlayerUnitPtr); 127 | 128 | if (aPlayerUnit == IntPtr.Zero) 129 | { 130 | throw new Exception("Player address is zero."); 131 | }*/ 132 | 133 | var playerName = Encoding.ASCII.GetString(Read(processHandle, PlayerUnit.UnitData, 16)).TrimEnd((char)0); 134 | var act = Read(processHandle, (IntPtr)PlayerUnit.pAct); 135 | var mapSeed = (uint)0; 136 | if (currentMapSeed == 0) 137 | { 138 | currentMapSeed = act.MapSeed; 139 | } 140 | mapSeed = currentMapSeed; 141 | 142 | if (mapSeed <= 0 || mapSeed > 0xFFFFFFFF) 143 | { 144 | throw new Exception("Map seed is out of bounds."); 145 | } 146 | 147 | var actId = act.ActId; 148 | var actMisc = Read(processHandle, (IntPtr)act.ActMisc); 149 | var gameDifficulty = Difficulty.None; 150 | if(currentDifficulty == Difficulty.None) 151 | { 152 | currentDifficulty = actMisc.GameDifficulty; 153 | } 154 | gameDifficulty = currentDifficulty; 155 | 156 | if (!gameDifficulty.IsValid()) 157 | { 158 | throw new Exception("Game difficulty out of bounds."); 159 | } 160 | 161 | var path = Read(processHandle, (IntPtr)PlayerUnit.pPath); 162 | var positionX = path.DynamicX; 163 | var positionY = path.DynamicY; 164 | var room = Read(processHandle, (IntPtr)path.pRoom); 165 | var roomEx = Read(processHandle, (IntPtr)room.pRoomEx); 166 | var level = Read(processHandle, (IntPtr)roomEx.pLevel); 167 | var levelId = level.LevelId; 168 | 169 | if (!levelId.IsValid()) 170 | { 171 | throw new Exception("Level id out of bounds."); 172 | } 173 | 174 | var mapShownByte = Read(processHandle, IntPtr.Add(processAddress, Offsets.UiSettings)).MapShown; 175 | var mapShown = mapShownByte == 1; 176 | 177 | WarningMessages.Clear(); 178 | Monsters = GetMobs(processHandle, IntPtr.Add(processAddress, Offsets.UnitHashTable + (128 * 8))); 179 | 180 | return new GameData 181 | { 182 | PlayerPosition = new Point(positionX, positionY), 183 | MapSeed = mapSeed, 184 | Area = levelId, 185 | Difficulty = gameDifficulty, 186 | MapShown = mapShown, 187 | MainWindowHandle = gameProcess.MainWindowHandle, 188 | PlayerName = playerName 189 | }; 190 | } 191 | catch (Exception exception) 192 | { 193 | Console.WriteLine(exception.Message); 194 | ResetPlayerUnit(); 195 | return null; 196 | } 197 | finally 198 | { 199 | if (processHandle != IntPtr.Zero) 200 | { 201 | WindowsExternal.CloseHandle(processHandle); 202 | } 203 | } 204 | } 205 | unsafe public static List GetMobs(IntPtr processHandle, IntPtr startAddress) 206 | { 207 | var monList = new List(); 208 | 209 | var unitHashTable = Read(processHandle, startAddress); 210 | foreach (var pUnitAny in unitHashTable.UnitTable) 211 | { 212 | var pListNext = pUnitAny; 213 | 214 | while (pListNext != IntPtr.Zero) 215 | { 216 | var unitAny = Read(processHandle, pListNext); 217 | //why would we ever comment any of our code with anything useful? :D 218 | if (unitAny.Mode != 0 && unitAny.Mode != 12 && !NPCs.Dummies.TryGetValue(unitAny.TxtFileNo, out var _)) 219 | { 220 | 221 | var monData = Read(processHandle, unitAny.UnitData); 222 | var monStats = Read(processHandle, monData.pMonStats); 223 | var monNameBytes = new byte[monStats.Name.Length - 2]; 224 | Array.Copy(monStats.Name, 2, monNameBytes, 0, monNameBytes.Length); 225 | var monName = Encoding.ASCII.GetString(monNameBytes).TrimEnd((char)0); 226 | var monPath = Read(processHandle, (IntPtr)unitAny.pPath); 227 | var flag = Read(processHandle, IntPtr.Add(unitAny.UnitData, 24)); 228 | var newMon = new Monster() 229 | { 230 | Position = new Point(monPath.DynamicX, monPath.DynamicY), 231 | UniqueFlag = flag, 232 | Immunities = GetImmunes(processHandle, unitAny) 233 | }; 234 | var NPC = Enum.GetName(typeof(Npc), unitAny.TxtFileNo); 235 | 236 | var SuperUnique = false; 237 | var NameInWarnList = Array.Exists(Map.WarnImmuneNPC, element => (element == Enum.GetName(typeof(Npc), unitAny.TxtFileNo))); 238 | var NameInWarnList2 = false; 239 | if ((monData.MonsterType & MonsterTypeFlags.SuperUnique) == MonsterTypeFlags.SuperUnique) 240 | { 241 | NPCs.SuperUnique.TryGetValue(monName, out var SuperUniqueName); 242 | SuperUnique = NPCs.SuperUniqueName(monName) == SuperUniqueName; 243 | NameInWarnList2 = Array.Exists(Map.WarnImmuneNPC, element => (element == SuperUniqueName)); 244 | if (SuperUnique) 245 | { 246 | NPC = SuperUniqueName; 247 | } 248 | } 249 | if (NameInWarnList || (SuperUnique && NameInWarnList2)) 250 | { 251 | var immunestr = ""; 252 | foreach(Resist immunity in newMon.Immunities) 253 | { 254 | immunestr += immunity + ", "; 255 | } 256 | if (immunestr.Length > 2) 257 | { 258 | immunestr = immunestr.Remove(immunestr.Length - 2); 259 | WarningMessages.Add(NPC + " is immune to " + immunestr); 260 | } 261 | } 262 | monList.Add(newMon); 263 | } 264 | pListNext = (IntPtr)unitAny.pListNext; 265 | } 266 | } 267 | return monList; 268 | } 269 | 270 | public static Dictionary GetStats(IntPtr processHandle, UnitAny unit) 271 | { 272 | var _statListStruct = Read(processHandle, unit.StatsListEx); 273 | return Read(processHandle, _statListStruct.Stats.FirstStatPtr, Convert.ToInt32(_statListStruct.Stats.Size)).ToDictionary(s => s.Stat, s => s.Value); 274 | } 275 | public static List GetResists(IntPtr processHandle, UnitAny unit) 276 | { 277 | var stats = GetStats(processHandle, unit); 278 | 279 | stats.TryGetValue(Stat.STAT_DAMAGERESIST, out var dmgres); 280 | stats.TryGetValue(Stat.STAT_MAGICRESIST, out var magicres); 281 | stats.TryGetValue(Stat.STAT_FIRERESIST, out var fireres); 282 | stats.TryGetValue(Stat.STAT_LIGHTRESIST, out var lightres); 283 | stats.TryGetValue(Stat.STAT_COLDRESIST, out var coldres); 284 | stats.TryGetValue(Stat.STAT_POISONRESIST, out var poires); 285 | 286 | var _resists = new List { dmgres, magicres, fireres, lightres, coldres, poires }; 287 | 288 | return _resists; 289 | } 290 | public static List GetImmunes(IntPtr processHandle, UnitAny unit) 291 | { 292 | var resists = GetResists(processHandle, unit); 293 | var immunities = new List(); 294 | for (var i = 0; i < 6; i++) 295 | { 296 | if (resists[i] >= 100) 297 | { 298 | immunities.Add((Resist)i); 299 | } 300 | } 301 | var _immunes = immunities; 302 | return _immunes; 303 | } 304 | private static void ResetPlayerUnit() 305 | { 306 | PlayerUnit = default; 307 | PlayerUnitPtr = IntPtr.Zero; 308 | } 309 | 310 | public static T[] Read(IntPtr processHandle, IntPtr address, int count) where T : struct 311 | { 312 | var sz = Marshal.SizeOf(); 313 | var buf = new byte[sz * count]; 314 | WindowsExternal.ReadProcessMemory(processHandle, address, buf, buf.Length, out _); 315 | 316 | var handle = GCHandle.Alloc(buf, GCHandleType.Pinned); 317 | try 318 | { 319 | var result = new T[count]; 320 | for (var i = 0; i < count; i++) 321 | { 322 | result[i] = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject() + (i * sz), typeof(T)); 323 | } 324 | 325 | return result; 326 | } 327 | finally 328 | { 329 | handle.Free(); 330 | } 331 | } 332 | 333 | public static T Read(IntPtr processHandle, IntPtr address) where T : struct 334 | { 335 | return Read(processHandle, address, 1)[0]; 336 | } 337 | } 338 | } 339 | -------------------------------------------------------------------------------- /Types/GameObject.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2021 okaygo 3 | * 4 | * https://github.com/misterokaygo/MapAssist/ 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | **/ 19 | 20 | namespace MapAssist.Types 21 | { 22 | public enum GameObject 23 | { 24 | NotApplicable = -1, 25 | TestData1 = 0, 26 | Casket5 = 1, 27 | Shrine = 2, 28 | Casket6 = 3, 29 | LargeUrn1 = 4, 30 | LargeChestRight = 5, 31 | LargeChestLeft = 6, 32 | Barrel = 7, 33 | TowerTome = 8, 34 | Urn2 = 9, 35 | Bench = 10, 36 | BarrelExploding = 11, 37 | RogueFountain = 12, 38 | DoorGateLeft = 13, 39 | DoorGateRight = 14, 40 | DoorWoodenLeft = 15, 41 | DoorWoodenRight = 16, 42 | CairnStoneAlpha = 17, 43 | CairnStoneBeta = 18, 44 | CairnStoneGamma = 19, 45 | CairnStoneDelta = 20, 46 | CairnStoneLambda = 21, 47 | CairnStoneTheta = 22, 48 | DoorCourtyardLeft = 23, 49 | DoorCourtyardRight = 24, 50 | DoorCathedralDouble = 25, 51 | CainGibbet = 26, 52 | DoorMonasteryDoubleRight = 27, 53 | HoleAnim = 28, 54 | Brazier = 29, 55 | InifussTree = 30, 56 | Fountain = 31, 57 | Crucifix = 32, 58 | Candles1 = 33, 59 | Candles2 = 34, 60 | Standard1 = 35, 61 | Standard2 = 36, 62 | Torch1Tiki = 37, 63 | Torch2Wall = 38, 64 | RogueBonfire = 39, 65 | River1 = 40, 66 | River2 = 41, 67 | River3 = 42, 68 | River4 = 43, 69 | River5 = 44, 70 | AmbientSoundGenerator = 45, 71 | Crate = 46, 72 | AndarielDoor = 47, 73 | RogueTorch1 = 48, 74 | RogueTorch2 = 49, 75 | CasketR = 50, 76 | CasketL = 51, 77 | Urn3 = 52, 78 | Casket = 53, 79 | RogueCorpse1 = 54, 80 | RogueCorpse2 = 55, 81 | RogueCorpseRolling = 56, 82 | CorpseOnStick1 = 57, 83 | CorpseOnStick2 = 58, 84 | TownPortal = 59, 85 | PermanentTownPortal = 60, 86 | InvisibleObject = 61, 87 | DoorCathedralLeft = 62, 88 | DoorCathedralRight = 63, 89 | DoorWoodenLeft2 = 64, 90 | InvisibleRiverSound1 = 65, 91 | InvisibleRiverSound2 = 66, 92 | Ripple1 = 67, 93 | Ripple2 = 68, 94 | Ripple3 = 69, 95 | Ripple4 = 70, 96 | ForestNightSound1 = 71, 97 | ForestNightSound2 = 72, 98 | YetiDung = 73, 99 | TrappDoor = 74, 100 | DoorByAct2Dock = 75, 101 | SewerDrip = 76, 102 | HealthOrama = 77, 103 | InvisibleTownSound = 78, 104 | Casket3 = 79, 105 | Obelisk = 80, 106 | ForestAltar = 81, 107 | BubblingPoolOfBlood = 82, 108 | HornShrine = 83, 109 | HealingWell = 84, 110 | BullHealthShrine = 85, 111 | SteleDesertMagicShrine = 86, 112 | TombLargeChestL = 87, 113 | TombLargeChestR = 88, 114 | Sarcophagus = 89, 115 | DesertObelisk = 90, 116 | TombDoorLeft = 91, 117 | TombDoorRight = 92, 118 | InnerHellManaShrine = 93, 119 | LargeUrn4 = 94, 120 | LargeUrn5 = 95, 121 | InnerHellHealthShrine = 96, 122 | InnerHellShrine = 97, 123 | TombDoorLeft2 = 98, 124 | TombDoorRight2 = 99, 125 | DurielsLairPortal = 100, 126 | Brazier3 = 101, 127 | FloorBrazier = 102, 128 | Flies = 103, 129 | ArmorStandRight = 104, 130 | ArmorStandLeft = 105, 131 | WeaponRackRight = 106, 132 | WeaponRackLeft = 107, 133 | Malus = 108, 134 | PalaceHealthShrine = 109, 135 | Drinker = 110, 136 | Fountain1 = 111, 137 | Gesturer = 112, 138 | DesertFountain = 113, 139 | Turner = 114, 140 | Fountain3 = 115, 141 | SnakeWomanShrine = 116, 142 | JungleTorch = 117, 143 | Fountain4 = 118, 144 | WaypointPortal = 119, 145 | DungeonHealthShrine = 120, 146 | JerhynPlaceHolder1 = 121, 147 | JerhynPlaceHolder2 = 122, 148 | InnerHellShrine2 = 123, 149 | InnerHellShrine3 = 124, 150 | InnerHellHiddenStash = 125, 151 | InnerHellSkullPile = 126, 152 | InnerHellHiddenStash2 = 127, 153 | InnerHellHiddenStash3 = 128, 154 | SecretDoor1 = 129, 155 | Act1WildernessWell = 130, 156 | VileDogAfterglow = 131, 157 | CathedralWell = 132, 158 | ArcaneSanctuaryShrine = 133, 159 | DesertShrine2 = 134, 160 | DesertShrine3 = 135, 161 | DesertShrine1 = 136, 162 | DesertWell = 137, 163 | CaveWell = 138, 164 | Act1LargeChestRight = 139, 165 | Act1TallChestRight = 140, 166 | Act1MediumChestRight = 141, 167 | DesertJug1 = 142, 168 | DesertJug2 = 143, 169 | Act1LargeChest1 = 144, 170 | InnerHellWaypoint = 145, 171 | Act2MediumChestRight = 146, 172 | Act2LargeChestRight = 147, 173 | Act2LargeChestLeft = 148, 174 | TaintedSunAltar = 149, 175 | DesertShrine5 = 150, 176 | DesertShrine4 = 151, 177 | HoradricOrifice = 152, 178 | TyraelsDoor = 153, 179 | GuardCorpse = 154, 180 | HiddenStashRock = 155, 181 | Act2Waypoint = 156, 182 | Act1WildernessWaypoint = 157, 183 | SkeletonCorpseIsAnOxymoron = 158, 184 | HiddenStashRockB = 159, 185 | SmallFire = 160, 186 | MediumFire = 161, 187 | LargeFire = 162, 188 | Act1CliffHidingSpot = 163, 189 | ManaWell1 = 164, 190 | ManaWell2 = 165, 191 | ManaWell3 = 166, 192 | ManaWell4 = 167, 193 | ManaWell5 = 168, 194 | HollowLog = 169, 195 | JungleHealWell = 170, 196 | SkeletonCorpseIsStillAnOxymoron = 171, 197 | DesertHealthShrine = 172, 198 | ManaWell7 = 173, 199 | LooseRock = 174, 200 | LooseBoulder = 175, 201 | MediumChestLeft = 176, 202 | LargeChestLeft2 = 177, 203 | GuardCorpseOnAStick = 178, 204 | Bookshelf1 = 179, 205 | Bookshelf2 = 180, 206 | JungleChest = 181, 207 | TombCoffin = 182, 208 | JungleMediumChestLeft = 183, 209 | JungleShrine2 = 184, 210 | JungleStashObject1 = 185, 211 | JungleStashObject2 = 186, 212 | JungleStashObject3 = 187, 213 | JungleStashObject4 = 188, 214 | DummyCainPortal = 189, 215 | JungleShrine3 = 190, 216 | JungleShrine4 = 191, 217 | TeleportationPad1 = 192, 218 | LamEsensTome = 193, 219 | StairsL = 194, 220 | StairsR = 195, 221 | FloorTrap = 196, 222 | JungleShrine5 = 197, 223 | TallChestLeft = 198, 224 | MephistoShrine1 = 199, 225 | MephistoShrine2 = 200, 226 | MephistoShrine3 = 201, 227 | MephistoManaShrine = 202, 228 | MephistoLair = 203, 229 | StashBox = 204, 230 | StashAltar = 205, 231 | MafistoHealthShrine = 206, 232 | Act3WaterRocks = 207, 233 | Basket1 = 208, 234 | Basket2 = 209, 235 | Act3WaterLogs = 210, 236 | Act3WaterRocksGirl = 211, 237 | Act3WaterBubbles = 212, 238 | Act3WaterLogsX = 213, 239 | Act3WaterRocksB = 214, 240 | Act3WaterRocksGirlC = 215, 241 | Act3WaterRocksY = 216, 242 | Act3WaterLogsZ = 217, 243 | WebCoveredTree1 = 218, 244 | WebCoveredTree2 = 219, 245 | WebCoveredTree3 = 220, 246 | WebCoveredTree4 = 221, 247 | Pillar = 222, 248 | Cocoon = 223, 249 | Cocoon2 = 224, 250 | SkullPileH1 = 225, 251 | OuterHellShrine = 226, 252 | Act3WaterRocksGirlW = 227, 253 | Act3BigLog = 228, 254 | SlimeDoor1 = 229, 255 | SlimeDoor2 = 230, 256 | OuterHellShrine2 = 231, 257 | OuterHellShrine3 = 232, 258 | PillarH2 = 233, 259 | Act3BigLogC = 234, 260 | Act3BigLogD = 235, 261 | HellHealthShrine = 236, 262 | Act3TownWaypoint = 237, 263 | WaypointH = 238, 264 | BurningBodyTown = 239, 265 | Gchest1L = 240, 266 | Gchest2R = 241, 267 | Gchest3R = 242, 268 | GLchest3L = 243, 269 | SewersRatNest = 244, 270 | BurningBodyTown2 = 245, 271 | SewersRatNest2 = 246, 272 | Act1BedBed1 = 247, 273 | Act1BedBed2 = 248, 274 | HellManaShrine = 249, 275 | ExplodingCow = 250, 276 | GidbinnAltar = 251, 277 | GidbinnAltarDecoy = 252, 278 | DiabloRightLight = 253, 279 | DiabloLeftLight = 254, 280 | DiabloStartPoint = 255, 281 | Act1CabinStool = 256, 282 | Act1CabinWood = 257, 283 | Act1CabinWood2 = 258, 284 | HellSkeletonSpawnNW = 259, 285 | Act1HolyShrine = 260, 286 | TombsFloorTrapSpikes = 261, 287 | Act1CathedralShrine = 262, 288 | Act1JailShrine1 = 263, 289 | Act1JailShrine2 = 264, 290 | Act1JailShrine3 = 265, 291 | MaggotLairGooPile = 266, 292 | Bank = 267, 293 | WirtCorpse = 268, 294 | GoldPlaceHolder = 269, 295 | GuardCorpse2 = 270, 296 | DeadVillager1 = 271, 297 | DeadVillager2 = 272, 298 | DummyFlameNoDamage = 273, 299 | TinyPixelShapedThingie = 274, 300 | CavesHealthShrine = 275, 301 | CavesManaShrine = 276, 302 | CaveMagicShrine = 277, 303 | Act3DungeonManaShrine = 278, 304 | Act3SewersMagicShrine1 = 279, 305 | Act3SewersHealthWell = 280, 306 | Act3SewersManaWell = 281, 307 | Act3SewersMagicShrine2 = 282, 308 | Act2BrazierCeller = 283, 309 | Act2TombAnubisCoffin = 284, 310 | Act2Brazier = 285, 311 | Act2BrazierTall = 286, 312 | Act2BrazierSmall = 287, 313 | Act2CellerWaypoint = 288, 314 | HarumBedBed = 289, 315 | IronGrateDoorLeft = 290, 316 | IronGrateDoorRight = 291, 317 | WoodenGrateDoorLeft = 292, 318 | WoodenGrateDoorRight = 293, 319 | WoodenDoorLeft = 294, 320 | WoodenDoorRight = 295, 321 | TombsWallTorchLeft = 296, 322 | TombsWallTorchRight = 297, 323 | ArcaneSanctuaryPortal = 298, 324 | Act2HaramMagicShrine1 = 299, 325 | Act2HaramMagicShrine2 = 300, 326 | MaggotHealthWell = 301, 327 | MaggotManaWell = 302, 328 | ArcaneSanctuaryMagicShrine = 303, 329 | TeleportationPad2 = 304, 330 | TeleportationPad3 = 305, 331 | TeleportationPad4 = 306, 332 | DummyArcaneThing1 = 307, 333 | DummyArcaneThing2 = 308, 334 | DummyArcaneThing3 = 309, 335 | DummyArcaneThing4 = 310, 336 | DummyArcaneThing5 = 311, 337 | DummyArcaneThing6 = 312, 338 | DummyArcaneThing7 = 313, 339 | HaremDeadGuard1 = 314, 340 | HaremDeadGuard2 = 315, 341 | HaremDeadGuard3 = 316, 342 | HaremDeadGuard4 = 317, 343 | HaremEunuchBlocker = 318, 344 | ArcaneHealthWell = 319, 345 | ArcaneManaWell = 320, 346 | TestData2 = 321, 347 | Act2TombWell = 322, 348 | Act2SewerWaypoint = 323, 349 | Act3TravincalWaypoint = 324, 350 | Act3SewerMagicShrine = 325, 351 | Act3SewerDeadBody = 326, 352 | Act3SewerTorch = 327, 353 | Act3KurastTorch = 328, 354 | MafistoLargeChestLeft = 329, 355 | MafistoLargeChestRight = 330, 356 | MafistoMediumChestLeft = 331, 357 | MafistoMediumChestRight = 332, 358 | SpiderLairLargeChestLeft = 333, 359 | SpiderLairTallChestLeft = 334, 360 | SpiderLairMediumChestRight = 335, 361 | SpiderLairTallChestRight = 336, 362 | SteegStone = 337, 363 | GuildVault = 338, 364 | TrophyCase = 339, 365 | MessageBoard = 340, 366 | MephistoBridge = 341, 367 | HellGate = 342, 368 | Act3KurastManaWell = 343, 369 | Act3KurastHealthWell = 344, 370 | HellFire1 = 345, 371 | HellFire2 = 346, 372 | HellFire3 = 347, 373 | HellLava1 = 348, 374 | HellLava2 = 349, 375 | HellLava3 = 350, 376 | HellLightSource1 = 351, 377 | HellLightSource2 = 352, 378 | HellLightSource3 = 353, 379 | HoradricCubeChest = 354, 380 | HoradricScrollChest = 355, 381 | StaffOfKingsChest = 356, 382 | YetAnotherTome = 357, 383 | HellBrazier1 = 358, 384 | HellBrazier2 = 359, 385 | DungeonRockPile = 360, 386 | Act3DungeonMagicShrine = 361, 387 | Act3DungeonBasket = 362, 388 | OuterHellHungSkeleton = 363, 389 | GuyForDungeon = 364, 390 | Act3DungeonCasket = 365, 391 | Act3SewerStairs = 366, 392 | Act3SewerStairsToLevel3 = 367, 393 | DarkWandererStartPosition = 368, 394 | TrappedSoulPlaceHolder = 369, 395 | Act3TownTorch = 370, 396 | LargeChestR = 371, 397 | InnerHellBoneChest = 372, 398 | HellSkeletonSpawnNE = 373, 399 | Act3WaterFog = 374, 400 | DummyNotUsed = 375, 401 | HellForge = 376, 402 | GuildPortal = 377, 403 | HratliStartPosition = 378, 404 | HratliEndPosition = 379, 405 | BurningTrappedSoul1 = 380, 406 | BurningTrappedSoul2 = 381, 407 | NatalyaStartPosition = 382, 408 | StuckedTrappedSoul1 = 383, 409 | StuckedTrappedSoul2 = 384, 410 | CainStartPosition = 385, 411 | StairSR = 386, 412 | ArcaneLargeChestLeft = 387, 413 | ArcaneCasket = 388, 414 | ArcaneLargeChestRight = 389, 415 | ArcaneSmallChestLeft = 390, 416 | ArcaneSmallChestRight = 391, 417 | DiabloSeal1 = 392, 418 | DiabloSeal2 = 393, 419 | DiabloSeal3 = 394, 420 | DiabloSeal4 = 395, 421 | DiabloSeal5 = 396, 422 | SparklyChest = 397, 423 | PandamoniumFortressWaypoint = 398, 424 | InnerHellFissure = 399, 425 | HellMesaBrazier = 400, 426 | Smoke = 401, 427 | ValleyWaypoint = 402, 428 | HellBrazier3 = 403, 429 | CompellingOrb = 404, 430 | KhalimChest1 = 405, 431 | KhalimChest2 = 406, 432 | KhalimChest3 = 407, 433 | SiegeMachineControl = 408, 434 | PotOTorch = 409, 435 | PyoxFirePit = 410, 436 | ExpansionChestRight = 413, 437 | ExpansionWildernessShrine1 = 414, 438 | ExpansionWildernessShrine2 = 415, 439 | ExpansionHiddenStash = 416, 440 | ExpansionWildernessFlag = 417, 441 | ExpansionWildernessBarrel = 418, 442 | ExpansionSiegeBarrel = 419, 443 | ExpansionWoodChestLeft = 420, 444 | ExpansionWildernessShrine3 = 421, 445 | ExpansionManaShrine = 422, 446 | ExpansionHealthShrine = 423, 447 | BurialChestLeft = 424, 448 | BurialChestRight = 425, 449 | ExpansionWell = 426, 450 | ExpansionWildernessShrine4 = 427, 451 | ExpansionWildernessShrine5 = 428, 452 | ExpansionWaypoint = 429, 453 | ExpansionChestLeft = 430, 454 | ExpansionWoodChestRight = 431, 455 | ExpansionSmallChestLeft = 432, 456 | ExpansionSmallChestRight = 433, 457 | ExpansionTorch1 = 434, 458 | ExpansionCampFire = 435, 459 | ExpansionTownTorch = 436, 460 | ExpansionTorch2 = 437, 461 | ExpansionBurningBodies = 438, 462 | ExpansionBurningPit = 439, 463 | ExpansionTribalFlag = 440, 464 | ExpansionTownFlag = 441, 465 | ExpansionChandelier = 442, 466 | ExpansionJar1 = 443, 467 | ExpansionJar2 = 444, 468 | ExpansionJar3 = 445, 469 | ExpansionSwingingHeads = 446, 470 | ExpansionWildernessPole = 447, 471 | AnimatedSkullAndRockPile = 448, 472 | ExpansionTownGate = 449, 473 | SkullAndRockPile = 450, 474 | SiegeHellGate = 451, 475 | EnemyCampBanner1 = 452, 476 | EnemyCampBanner2 = 453, 477 | ExpansionExplodingChest = 454, 478 | ExpansionSpecialChest = 455, 479 | ExpansionDeathPole = 456, 480 | ExpansionDeathPoleLeft = 457, 481 | TempleAltar = 458, 482 | DrehyaTownStartPosition = 459, 483 | DrehyaWildernessStartPosition = 460, 484 | NihlathakTownStartPosition = 461, 485 | NihlathakWildernessStartPosition = 462, 486 | IceCaveHiddenStash = 463, 487 | IceCaveHealthShrine = 464, 488 | IceCaveManaShrine = 465, 489 | IceCaveEvilUrn = 466, 490 | IceCaveJar1 = 467, 491 | IceCaveJar2 = 468, 492 | IceCaveJar3 = 469, 493 | IceCaveJar4 = 470, 494 | IceCaveJar5 = 471, 495 | IceCaveMagicShrine = 472, 496 | CagedWussie = 473, 497 | AncientStatue3 = 474, 498 | AncientStatue1 = 475, 499 | AncientStatue2 = 476, 500 | DeadBarbarian = 477, 501 | ClientSmoke = 478, 502 | IceCaveMagicShrine2 = 479, 503 | IceCaveTorch1 = 480, 504 | IceCaveTorch2 = 481, 505 | ExpansionTikiTorch = 482, 506 | WorldstoneManaShrine = 483, 507 | WorldstoneHealthShrine = 484, 508 | WorldstoneTomb1 = 485, 509 | WorldstoneTomb2 = 486, 510 | WorldstoneTomb3 = 487, 511 | WorldstoneMagicShrine = 488, 512 | WorldstoneTorch1 = 489, 513 | WorldstoneTorch2 = 490, 514 | ExpansionSnowyManaShrine1 = 491, 515 | ExpansionSnowyHealthShrine = 492, 516 | ExpansionSnowyWell = 493, 517 | WorldstoneWaypoint = 494, 518 | ExpansionSnowyMagicShrine2 = 495, 519 | ExpansionWildernessWaypoint = 496, 520 | ExpansionSnowyMagicShrine3 = 497, 521 | WorldstoneWell = 498, 522 | WorldstoneMagicShrine2 = 499, 523 | ExpansionSnowyObject1 = 500, 524 | ExpansionSnowyWoodChestLeft = 501, 525 | ExpansionSnowyWoodChestRight = 502, 526 | WorldstoneMagicShrine3 = 503, 527 | ExpansionSnowyWoodChest2Left = 504, 528 | ExpansionSnowyWoodChest2Right = 505, 529 | SnowySwingingHeads = 506, 530 | SnowyDebris = 507, 531 | PenBreakableDoor = 508, 532 | ExpansionTempleMagicShrine1 = 509, 533 | ExpansionSnowyPoleMR = 510, 534 | IceCaveWaypoint = 511, 535 | ExpansionTempleMagicShrine2 = 512, 536 | ExpansionTempleWell = 513, 537 | ExpansionTempleTorch1 = 514, 538 | ExpansionTempleTorch2 = 515, 539 | ExpansionTempleObject1 = 516, 540 | ExpansionTempleObject2 = 517, 541 | WorldstoneMrBox = 518, 542 | IceCaveWell = 519, 543 | ExpansionTempleMagicShrine = 520, 544 | ExpansionTempleHealthShrine = 521, 545 | ExpansionTempleManaShrine = 522, 546 | BlacksmithForge = 523, 547 | WorldstoneTomb1Left = 524, 548 | WorldstoneTomb2Left = 525, 549 | WorldstoneTomb3Left = 526, 550 | IceCaveBubblesU = 527, 551 | IceCaveBubblesS = 528, 552 | RedBaalsLairTomb1 = 529, 553 | RedBaalsLairTomb1Left = 530, 554 | RedBaalsLairTomb2 = 531, 555 | RedBaalsLairTomb2Left = 532, 556 | RedBaalsLairTomb3 = 533, 557 | RedBaalsLairTomb3Left = 534, 558 | RedBaalsLairMrBox = 535, 559 | RedBaalsLairTorch1 = 536, 560 | RedBaalsLairTorch2 = 537, 561 | CandlesTemple = 538, 562 | TempleWaypoint = 539, 563 | ExpansionDeadPerson1 = 540, 564 | TempleGroundTomb = 541, 565 | LarzukGreeting = 542, 566 | LarzukStandard = 543, 567 | TempleGroundTombLeft = 544, 568 | ExpansionDeadPerson2 = 545, 569 | AncientsAltar = 546, 570 | ArreatSummitDoorToWorldstone = 547, 571 | ExpansionWeaponRackRight = 548, 572 | ExpansionWeaponRackLeft = 549, 573 | ExpansionArmorStandRight = 550, 574 | ExpansionArmorStandLeft = 551, 575 | ArreatsSummitTorch2 = 552, 576 | ExpansionFuneralSpire = 553, 577 | ExpansionBurningLogs = 554, 578 | IceCaveSteam = 555, 579 | ExpansionDeadPerson3 = 556, 580 | BaalsLair = 557, 581 | FrozenAnya = 558, 582 | BBQBunny = 559, 583 | BaalTorchBig = 560, 584 | InvisibleAncient = 561, 585 | InvisibleBase = 562, 586 | BaalsPortal = 563, 587 | ArreatSummitDoor = 564, 588 | LastPortal = 565, 589 | LastLastPortal = 566, 590 | ZooTestData = 567, 591 | KeeperTestData = 568, 592 | BaalsPortal2 = 569, 593 | FirePlaceGuy = 570, 594 | DoorBlocker1 = 571, 595 | DoorBlocker2 = 572, 596 | // Added manually 597 | GoodChest = 580, 598 | NotSoGoodChest = 581 599 | }; 600 | } 601 | --------------------------------------------------------------------------------