diff --git a/.gitignore b/.gitignore index b9b063f..6c68121 100644 --- a/.gitignore +++ b/.gitignore @@ -370,3 +370,11 @@ FodyWeavers.xsd db/data/pgdata/ db/pgadmin/* !db/pgadmin/pgpass +/src/DiIiS-NA/config.ini +/src/DiIiS-NA/database.Account.config +/src/DiIiS-NA/database.Worlds.config +/src/DiIiS-NA/database.Account.Debug.config +/src/DiIiS-NA/database.Worlds.Debug.config + +# Generated config.mods.json +config.mods.json diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..464df45 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +# Use the official .NET SDK image to build the application +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +WORKDIR /app + +# Copy the project file and restore dependencies +COPY ["src/DiIiS-NA/Blizzless.csproj", "src/DiIiS-NA/"] +RUN dotnet restore "src/DiIiS-NA/Blizzless.csproj" + +# Copy the rest of the project files and build the application +COPY ["src/", "src/"] +WORKDIR "/app/src/DiIiS-NA" +RUN dotnet publish "Blizzless.csproj" -c Release --runtime linux-x64 --self-contained true -o /app/publish + +# Use the official .NET runtime image to run the application +FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS runtime +WORKDIR /app + +# Copy the published application from the build stage +COPY --from=build /app/publish . + +# Expose the port your application is running on (if needed) +EXPOSE 1345 1119 83 2001 9800 9100 +# Start the application +ENTRYPOINT ["./Blizzless"] \ No newline at end of file diff --git a/README.md b/README.md index 5db45c2..efa6561 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,14 @@ DiIiS is a fully-functional open-source local server for [Diablo III: Reaper of Souls](https://eu.diablo3.blizzard.com). +# Development + +Developers, please contribute using the branch: **_community_**, always create your branches from it. + +# Enthusiasts + +To test the server, use the **_test-stable_** or **_community_** branch + ## Features - Implemented account creation system, authorization and lobby. @@ -51,15 +59,20 @@ The currently supported version of the client: **2.7.4.84161** ### Compile and run 1. Install [.NET 7 SDK and runtime](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) (just runtime, not asp.net or desktop) 2. Go to the repo directory and compile the project using this command: - ```shell - dotnet publish ./src/DiIiS-NA/Blizzless.csproj --configuration Release --output ./publish - ``` -3. [Skip this stage for local game] Copy the [config.ini](configs/config.ini) file to the publish folder (It overwrites the default settings): - - Update the parameter entries with your IP record on the network: `BindIP` and `PublicIP`. -4. Go to the publish folder, launch Blizzless executable, wait until server start - it creates a hierarchy. -5. Create user account(s) using console: `!account add Login Password Tag` +```shell +dotnet publish ./src/DiIiS-NA/Blizzless.csproj --configuration Release --output ./publish +``` +3. __Skip this stage for local game__ Copy the [config.mods.json](https://github.com/blizzless/blizzless-diiis/blob/community/configs/config.mods.json) file to the folder, and modify however you want. A file will be generated automatically from the `config.ini` for now. +4. Update your `config.ini` file on the published folder with your network's IP records (`BindIP` and `PublicIP`) +5. Go to the publish folder, launch Blizzless executable, wait until server start - it creates a hierarchy. +6. Create user account(s) using console: `!account add Login Password Tag` + - Example: + - `!account add username@ YourPassword YourBattleTag` + - Creates an account with Login `username@`, password `YourPassword` and BattleTag `YourBattleTag` + - `!account add username@ YourPassword YourBattleTag owner` + - Creates an account with Login `username@`, password `YourPassword` and BattleTag `YourBattleTag` with rank `owner` -#### Example: +### Example: > !account add username@ YourPassword YourBattleTag @@ -129,6 +142,51 @@ The command system allows you to get control of the game world if you have right Check the [report form](docs/report-form.md) before submitting issue, this will help people save time! +# Development Roadmap – Diablo-like Server/Client +### 1️⃣ Rift / Greater Rift System + +GR closure: ensure the Greater Rift closes automatically after 15 minutes. +Exit portal: fix the teleport at the end of the GR so it appears and works correctly. +Resource consumption: make sure the GR Stone and gold are properly consumed when energizing the rift. +Death time penalty: implement the correct penalty (+5 seconds per death after the 3rd inside the GR). +Mob removal: clear all enemies after a GR is finished. +Next-level portal display: ensure the portal to the next GR level only appears when appropriate. +Level display bug: fix the issue that shows only GR level 13 Torment 2. +GR pillars validation: review and validate the behavior of GR pillars. + +### 2️⃣ Items & Crafting + +Kanai’s Cube: fix legendary power extraction so it correctly consumes the required items. +Enchant NPC: enable proper re-rolling of any item’s stats. +Ramaladni’s Gift: ensure it correctly adds a socket to weapons. +Gem validation: review the behavior of normal and legendary gems. +Affix validation: confirm that all item affixes work as intended. +Set bonus validation: review and adjust item set bonuses. +Legendary bonus validation: ensure legendary powers are correctly applied (including duplicate checks). +Boss drop validation: confirm that bosses drop the correct items. + +### 3️⃣ Progression & Gameplay + +Waypoints: + +Fix client crash when changing Sanctuary view with the + and – buttons. +Correctly display the map name when clicked. +Ensure teleporting through waypoints works reliably. +Normal rift teleport: fix the portal that remains after a normal rift is closed. +Character weapon display: fix the bug where the character’s weapon is not shown. +Difficulty save: store the last difficulty level used by the player for the next session. +NPC upgrade after level 10: validate that the NPC correctly consumes Death’s Breath when upgrading. + +### 4️⃣ Bounties & Rewards + +Bounty system: validate the full bounty system and its rewards. + +### Suggested Priorities +Critical stability: GR closure, resource consumption, exit teleport, and waypoint fixes. +Player progression: NPC upgrades, Kanai’s Cube, Ramaladni’s Gift, and difficulty saving. +Balance & content: validations for gems, affixes, set bonuses, legendary bonuses, and boss drops. +General improvements: visual fixes (weapon display) and overall gameplay polish. + # System requirements | | **Entry-level** | **Mid-range** | **High-end** | @@ -141,5 +199,12 @@ Check the [report form](docs/report-form.md) before submitting issue, this will You can see more screenshots [here](SCREENSHOTS.md) -![](pictures/ingame-screen-1.png) - +![](pictures/d30.PNG) +![](pictures/d31.PNG) +![](pictures/d32.PNG) +![](pictures/d33.PNG) +![](pictures/d34.PNG) +![](pictures/d35.PNG) +![](pictures/d36.PNG) +![](pictures/d37.PNG) +![](pictures/d38.PNG) diff --git a/Src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/QuestEvents/Implementations/Act I/SpawnSkeletons.cs b/Src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/QuestEvents/Implementations/Act I/SpawnSkeletons.cs new file mode 100644 index 0000000..ff7fe82 --- /dev/null +++ b/Src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/QuestEvents/Implementations/Act I/SpawnSkeletons.cs @@ -0,0 +1,92 @@ +using DiIiS_NA.Core.Logging; +using DiIiS_NA.GameServer.GSSystem.ActorSystem; +using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Hirelings; +using DiIiS_NA.GameServer.GSSystem.GameSystem; +using DiIiS_NA.GameServer.GSSystem.PlayerSystem; +using DiIiS_NA.GameServer.MessageSystem; +using System.Linq; +using System; +using System.Collections.Generic; +using DiIiS_NA.LoginServer.AccountsSystem; +using DiIiS_NA.GameServer.GSSystem.QuestSystem.QuestEvents; +using DiIiS_NA.GameServer.Core.Types.Math; +using DiIiS_NA.Core.Helpers.Math; +using DiIiS_NA.GameServer.Core.Types.TagMap; +using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Animation; +using System.Threading.Tasks; +using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Base; +using DiIiS_NA.D3_GameServer.Core.Types.SNO; + +namespace DiIiS_NA.GameServer.GSSystem.QuestSystem.QuestEvents.Implementations +{ + class SpawnSkeletons : QuestEvent + { + //ActorID: 0x7A3100DD + //ZombieSkinny_A_LeahInn.acr (2050031837) + //ActorSNOId: 0x00031971:ZombieSkinny_A_LeahInn.acr + + private static readonly Logger Logger = LogManager.CreateLogger(); + + public SpawnSkeletons() + : base(151124) + { + } + + public override void Execute(MapSystem.World world) + { + if (world.Game.Empty) return; + //Logger.Debug("SpawnSkeletons event started"); + Task.Delay(1000).ContinueWith(delegate + { + foreach (var plr in world.Game.Players.Values) + plr.InGameClient.SendMessage(new MessageSystem.Message.Definitions.Camera.CameraCriptedSequenceStartMessage() { Activate = true }); + var SkeletonKing_Bridge = world.GetActorBySNO(ActorSno._trdun_skeletonking_bridge_active); + Task.Delay(1000).ContinueWith(delegate + { + foreach (var plr in world.Game.Players.Values) + plr.InGameClient.SendMessage(new MessageSystem.Message.Definitions.Camera.CameraFocusMessage() { ActorID = (int)SkeletonKing_Bridge.DynamicID(plr), Duration = 1f, Snap = false }); + + StartConversation(world, 17923); + + SkeletonKing_Bridge.PlayAnimation(5, (AnimationSno)SkeletonKing_Bridge.AnimationSet.TagMapAnimDefault[AnimationSetKeys.Opening], 1f); + + world.BroadcastIfRevealed(plr => new SetIdleAnimationMessage + { + ActorID = SkeletonKing_Bridge.DynamicID(plr), + AnimationSNO = AnimationSetKeys.Open.ID, + }, SkeletonKing_Bridge); + + Task.Delay(3000).ContinueWith(delegate + { + foreach (var plr in world.Game.Players.Values) + { + plr.InGameClient.SendMessage(new BoolDataMessage(Opcodes.CameraTriggerFadeToBlackMessage) { Field0 = true }); + plr.InGameClient.SendMessage(new SimpleMessage(Opcodes.CameraSriptedSequenceStopMessage) { }); + } + }); + }); + }); + + + + var spawner = world.GetActorBySNO(ActorSno._trdun_rescuecainskelspawner); + while (spawner != null) + { + var monster = ActorSno._skeletonking_shield_skeleton; + world.SpawnMonster(monster, spawner.Position); + spawner.Destroy(); + spawner = world.GetActorBySNO(ActorSno._trdun_rescuecainskelspawner); + } + } + + private bool StartConversation(MapSystem.World world, Int32 conversationId) + { + foreach (var player in world.Players) + { + player.Value.Conversations.StartConversation(conversationId); + } + return true; + } + + } +} diff --git a/configs/config.ini b/configs/config.ini deleted file mode 100644 index 70c2f39..0000000 --- a/configs/config.ini +++ /dev/null @@ -1,114 +0,0 @@ -; -; # This is a template configuration file which can be modified as desired. -; -; # Community branch (recommended): https://github.com/blizzless/blizzless-diiis/tree/community -; # test-stable branch: https://github.com/blizzless/blizzless-diiis/ -; # Master branch: https://github.com/blizzless/blizzless-diiis/tree/master -; - -; Settings for Bnet -[Battle-Server] -Enabled = true -BindIP = 127.0.0.1 -WebPort = 9800 -Port = 1119 -MotdEnabled = true -Motd = Welcome to Blizzless D3! - -; ------------------------ -; [IWServer] -; IWServer = false - -; ------------------------ -; REST services for login (and others) -[REST] -IP = 127.0.0.1 -Public = true -PublicIP = 127.0.0.1 -PORT = 80 - -; ------------------------ -; Game server options and game-mods. -; -[Game-Server] -Enabled = true -CoreActive = true -BindIP = 127.0.0.1 -WebPort = 9001 -Port = 1345 -BindIPv6 = ::1 -DRLGemu = true - -; Modding of game (please check https://github.com/blizzless/blizzless-diiis/blob/community/docs/game-world-settings.md) -; - -; rates -RateExp = 1 -RateMoney = 1 -RateDrop = 1 -RateChangeDrop = 1 -RateMonsterHP = 1 -RateMonsterDMG = 1 -; items -ChanceHighQualityUnidentified = 30 -ChanceNormalUnidentified = 5 -; bosses -BossHealthMultiplier = 6 -BossDamageMultiplier = 3 -; nephalem -NephalemRiftProgressMultiplier = 1 -; health -HealthPotionRestorePercentage = 60 -HealthPotionCooldown = 30 -ResurrectionCharges = 3 -; waypoints -UnlockAllWaypoints = false -; player attribute modifier -StrengthMultiplier = 1 -StrengthParagonMultiplier = 1 -DexterityMultiplier = 1 -DexterityParagonMultiplier = 1 -IntelligenceMultiplier = 1 -IntelligenceParagonMultiplier = 1 -VitalityMultiplier = 1 -VitalityParagonMultiplier = 1 -; quests -AutoSaveQuests = false -; minimap -ForceMinimapVisibility = false - -; ------------------------ -; Network address translation -; -[NAT] -Enabled = True -; use your public IP -PublicIP = 127.0.0.1 - -; ------------------------ -; Where the outputs should be. -; Best for visualization (default): AnsiLog (target: Ansi) -; Best for debugging: ConsoleLog (target: console) -; Best for packet analysis: PacketLog (target: file) -; -[AnsiLog] -Enabled = true -Target = Ansi -IncludeTimeStamps = true -MinimumLevel = Debug -MaximumLevel = Fatal - -[ConsoleLog] -Enabled = false -Target = Console -IncludeTimeStamps = true -MinimumLevel = Debug -MaximumLevel = PacketDump - -[PacketLog] -Enabled = true -Target = file -FileName = packet.log -IncludeTimeStamps = true -MinimumLevel = Debug -MaximumLevel = PacketDump diff --git a/configs/config.mods.json b/configs/config.mods.json new file mode 100644 index 0000000..5341038 --- /dev/null +++ b/configs/config.mods.json @@ -0,0 +1,60 @@ +{ + "Rate": { + "Experience": 1.0, + "Money": 1.0, + "Drop": 1.0, + "ChangeDrop": 1.0 + }, + "Health": { + "PotionRestorePercentage": 60.0, + "PotionCooldown": 30.0, + "ResurrectionCharges": 3 + }, + "Monster": { + "HealthMultiplier": 1.0, + "DamageMultiplier": 1.0 + }, + "Boss": { + "HealthMultiplier": 6.0, + "DamageMultiplier": 3.0 + }, + "Quest": { + "AutoSave": false, + "UnlockAllWaypoints": false + }, + "Player": { + "Multipliers": { + "Strength": { + "Normal": 1.0, + "Paragon": 1.0 + }, + "Dexterity": { + "Normal": 1.0, + "Paragon": 1.0 + }, + "Intelligence": { + "Normal": 1.0, + "Paragon": 1.0 + }, + "Vitality": { + "Normal": 1.0, + "Paragon": 1.0 + } + } + }, + "Items": { + "UnidentifiedDropChances": { + "HighQuality": 30.0, + "NormalQuality": 5.0 + } + }, + "Minimap": { + "ForceVisibility": false + }, + "NephalemRift": { + "ProgressMultiplier": 1.0, + "AutoFinish": false, + "AutoFinishThreshold": 2, + "OrbsChance": 2.0 + } +} \ No newline at end of file diff --git a/db/docker-compose.yml b/db/docker-compose.yml index 22380c8..74622ef 100644 --- a/db/docker-compose.yml +++ b/db/docker-compose.yml @@ -1,50 +1,40 @@ -version: "3.9" - services: - postgres: - container_name: postgres_container - image: postgres:14 - environment: - POSTGRES_USER: "postgres" - POSTGRES_PASSWORD: "postgres" - PGDATA: "/var/lib/postgresql/data/pgdata" + diiis-na-server: + build: + context: . + dockerfile: Dockerfile + container_name: diiis-na-server volumes: - - ./data:/var/lib/postgresql/data - - ./initdb:/docker-entrypoint-initdb.d + - ./src/DiIiS-NA/config.ini:/app/config.ini ports: - - "5432:5432" - networks: - - postgres - restart: unless-stopped - deploy: - resources: - limits: - cpus: "1" - memory: 4G - - pgadmin: - container_name: pgadmin_container - image: dpage/pgadmin4:6 + - 83:83 + - 1119:1119 + - 1345:1345 + - 2001:2001 + - 9800:9800 + - 9100:9100 + + depends_on: + db: + condition: service_healthy + + db: + image: postgres:17 + container_name: diiis-na-db environment: - PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-pgadmin4@pgadmin.org} - PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-password} - PGADMIN_CONFIG_SERVER_MODE: "False" - PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: "False" - volumes: - - ./pgadmin:/var/lib/pgadmin - - ./servers.json:/pgadmin4/servers.json - + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=postgres + - POSTGRES_DB=diablo ports: - - "5555:80" - networks: - - postgres - restart: unless-stopped - deploy: - resources: - limits: - cpus: "0.5" - memory: 1G + - 5432:5432 + volumes: + - db-data:/var/lib/postgresql/data + - ./db/initdb:/docker-entrypoint-initdb.d + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 10s + timeout: 5s + retries: 5 -networks: - postgres: - driver: bridge +volumes: + db-data: diff --git a/db/data/postgresql.conf b/db_old/data/postgresql.conf similarity index 100% rename from db/data/postgresql.conf rename to db_old/data/postgresql.conf diff --git a/db_old/docker-compose.yml b/db_old/docker-compose.yml new file mode 100644 index 0000000..22380c8 --- /dev/null +++ b/db_old/docker-compose.yml @@ -0,0 +1,50 @@ +version: "3.9" + +services: + postgres: + container_name: postgres_container + image: postgres:14 + environment: + POSTGRES_USER: "postgres" + POSTGRES_PASSWORD: "postgres" + PGDATA: "/var/lib/postgresql/data/pgdata" + volumes: + - ./data:/var/lib/postgresql/data + - ./initdb:/docker-entrypoint-initdb.d + ports: + - "5432:5432" + networks: + - postgres + restart: unless-stopped + deploy: + resources: + limits: + cpus: "1" + memory: 4G + + pgadmin: + container_name: pgadmin_container + image: dpage/pgadmin4:6 + environment: + PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-pgadmin4@pgadmin.org} + PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-password} + PGADMIN_CONFIG_SERVER_MODE: "False" + PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: "False" + volumes: + - ./pgadmin:/var/lib/pgadmin + - ./servers.json:/pgadmin4/servers.json + + ports: + - "5555:80" + networks: + - postgres + restart: unless-stopped + deploy: + resources: + limits: + cpus: "0.5" + memory: 1G + +networks: + postgres: + driver: bridge diff --git a/db_old/initdb/dump.sql b/db_old/initdb/dump.sql new file mode 100644 index 0000000..e1b0df1 --- /dev/null +++ b/db_old/initdb/dump.sql @@ -0,0 +1,2423 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 14.5 (Debian 14.5-1.pgdg110+1) +-- Dumped by pg_dump version 14.4 + +-- Started on 2022-08-18 16:47:30 UTC + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + + +CREATE DATABASE diiis WITH OWNER = postgres ENCODING = 'UTF8' LC_COLLATE = 'en_US.utf8' LC_CTYPE = 'en_US.utf8' TABLESPACE = pg_default; + +CREATE DATABASE worlds WITH OWNER = postgres ENCODING = 'UTF8' LC_COLLATE = 'en_US.utf8' LC_CTYPE = 'en_US.utf8' TABLESPACE = pg_default; +-- +-- TOC entry 3546 (class 1262 OID 24881) +-- Name: worlds; Type: DATABASE; Schema: -; Owner: postgres +-- + +\connect worlds + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- TOC entry 209 (class 1259 OID 25184) +-- Name: DRLG_Container; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public."DRLG_Container" ( + id integer NOT NULL, + worldsno bigint, + rangeofscenes bigint, + params bigint +); + + +ALTER TABLE public."DRLG_Container" OWNER TO postgres; + +-- +-- TOC entry 210 (class 1259 OID 25187) +-- Name: DRLG_Container_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public."DRLG_Container_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public."DRLG_Container_id_seq" OWNER TO postgres; + +-- +-- TOC entry 3548 (class 0 OID 0) +-- Dependencies: 210 +-- Name: DRLG_Container_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE public."DRLG_Container_id_seq" OWNED BY public."DRLG_Container".id; + + +-- +-- TOC entry 211 (class 1259 OID 25188) +-- Name: DRLG_Tile; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public."DRLG_Tile" ( + id integer NOT NULL, + head_container integer, + type integer, + snohandle_id integer, + snolevelarea integer, + snomusic integer, + snoweather integer +); + + +ALTER TABLE public."DRLG_Tile" OWNER TO postgres; + +-- +-- TOC entry 212 (class 1259 OID 25191) +-- Name: DRLG_Tile_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public."DRLG_Tile_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public."DRLG_Tile_id_seq" OWNER TO postgres; + +-- +-- TOC entry 3549 (class 0 OID 0) +-- Dependencies: 212 +-- Name: DRLG_Tile_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE public."DRLG_Tile_id_seq" OWNED BY public."DRLG_Tile".id; + + +-- +-- TOC entry 213 (class 1259 OID 25192) +-- Name: account_relations; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.account_relations ( + id bigint NOT NULL, + listowner_id bigint, + listtarget_id bigint, + type character varying(255) DEFAULT 'FRIEND'::character varying NOT NULL +); + + +ALTER TABLE public.account_relations OWNER TO postgres; + +-- +-- TOC entry 214 (class 1259 OID 25196) +-- Name: account_relations_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.account_relations_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.account_relations_seq OWNER TO postgres; + +-- +-- TOC entry 215 (class 1259 OID 25197) +-- Name: accounts; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.accounts ( + id bigint NOT NULL, + email character varying(255), + banned boolean DEFAULT false NOT NULL, + salt bytea, + passwordverifier bytea, + saltedticket character varying(255), + battletagname character varying(255), + hashcode integer, + referralcode integer, + inviteeaccount_id bigint, + money bigint DEFAULT 0, + userlevel character varying(255), + lastonline bigint, + hasrename boolean DEFAULT false NOT NULL, + renamecooldown bigint DEFAULT 0 +); + + +ALTER TABLE public.accounts OWNER TO postgres; + +-- +-- TOC entry 216 (class 1259 OID 25206) +-- Name: accounts_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.accounts_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.accounts_seq OWNER TO postgres; + +-- +-- TOC entry 217 (class 1259 OID 25207) +-- Name: achievements; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.achievements ( + id bigint NOT NULL, + dbgameaccount_id bigint, + achievementid bigint, + completetime integer, + ishardcore boolean DEFAULT false NOT NULL, + quantity integer DEFAULT 0, + criteria bytea +); + + +ALTER TABLE public.achievements OWNER TO postgres; + +-- +-- TOC entry 218 (class 1259 OID 25214) +-- Name: achievements_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.achievements_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.achievements_seq OWNER TO postgres; + +-- +-- TOC entry 219 (class 1259 OID 25215) +-- Name: collection_editions; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.collection_editions ( + id bigint NOT NULL, + setid integer, + dbaccount_id bigint, + claimed boolean DEFAULT false NOT NULL, + claimedtoon_id bigint, + claimedhardcore boolean DEFAULT false NOT NULL +); + + +ALTER TABLE public.collection_editions OWNER TO postgres; + +-- +-- TOC entry 220 (class 1259 OID 25220) +-- Name: collection_editions_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.collection_editions_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.collection_editions_seq OWNER TO postgres; + +-- +-- TOC entry 221 (class 1259 OID 25221) +-- Name: craft_data; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.craft_data ( + id bigint NOT NULL, + dbgameaccount_id bigint, + ishardcore boolean, + isseasoned boolean, + artisan character varying(255), + level integer, + learnedrecipes bytea NOT NULL +); + + +ALTER TABLE public.craft_data OWNER TO postgres; + +-- +-- TOC entry 222 (class 1259 OID 25226) +-- Name: craft_data_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.craft_data_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.craft_data_seq OWNER TO postgres; + +-- +-- TOC entry 223 (class 1259 OID 25227) +-- Name: game_accounts; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.game_accounts ( + id bigint NOT NULL, + dbaccount_id bigint, + lastonline bigint, + flags integer, + banner bytea, + uiprefs bytea, + uisettings bytea, + seentutorials bytea, + bossprogress bytea, + stashicons bytea, + paragonlevel integer, + paragonlevelhardcore integer, + experience integer, + experiencehardcore integer, + lastplayedhero_id bigint, + gold bigint, + hardcoregold bigint, + platinum integer, + hardplatinum integer, + rmtcurrency bigint, + hardrmtcurrency bigint, + bloodshards integer, + hardcorebloodshards integer, + stashsize integer, + hardcorestashsize integer, + seasonstashsize integer, + hardseasonstashsize integer, + eliteskilled bigint, + totalkilled bigint, + totalgold bigint, + hardtotalgold bigint, + totalbloodshards integer, + hardtotalbloodshards integer, + totalbounties integer DEFAULT 0 NOT NULL, + totalbountieshardcore integer DEFAULT 0 NOT NULL, + pvptotalkilled bigint, + hardpvptotalkilled bigint, + pvptotalwins bigint, + hardpvptotalwins bigint, + pvptotalgold bigint, + hardpvptotalgold bigint, + craftitem1 integer, + hardcraftitem1 integer, + craftitem2 integer, + hardcraftitem2 integer, + craftitem3 integer, + hardcraftitem3 integer, + craftitem4 integer, + hardcraftitem4 integer, + craftitem5 integer, + hardcraftitem5 integer, + vialofputridness integer, + hardvialofputridness integer, + idolofterror integer, + hardidolofterror integer, + heartoffright integer, + hardheartoffright integer, + leorikkey integer, + hardleorikkey integer, + bigportalkey integer, + hardbigportalkey integer, + horadrica1 integer, + hardhoradrica1 integer, + horadrica2 integer, + hardhoradrica2 integer, + horadrica3 integer, + hardhoradrica3 integer, + horadrica4 integer, + hardhoradrica4 integer, + horadrica5 integer, + hardhoradrica5 integer +); + + +ALTER TABLE public.game_accounts OWNER TO postgres; + +-- +-- TOC entry 224 (class 1259 OID 25234) +-- Name: game_accounts_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.game_accounts_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.game_accounts_seq OWNER TO postgres; + +-- +-- TOC entry 225 (class 1259 OID 25235) +-- Name: global_params; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.global_params ( + id bigint NOT NULL, + name character varying(255), + value bigint +); + + +ALTER TABLE public.global_params OWNER TO postgres; + +-- +-- TOC entry 226 (class 1259 OID 25238) +-- Name: global_params_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.global_params_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.global_params_seq OWNER TO postgres; + +-- +-- TOC entry 227 (class 1259 OID 25239) +-- Name: guild_members; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.guild_members ( + id bigint NOT NULL, + dbguild_id bigint, + dbgameaccount_id bigint, + note character varying(50), + rank integer +); + + +ALTER TABLE public.guild_members OWNER TO postgres; + +-- +-- TOC entry 228 (class 1259 OID 25242) +-- Name: guild_news; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.guild_news ( + id bigint NOT NULL, + dbguild_id bigint, + dbgameaccount_id bigint, + type integer, + "time" bigint, + data bytea +); + + +ALTER TABLE public.guild_news OWNER TO postgres; + +-- +-- TOC entry 229 (class 1259 OID 25247) +-- Name: guildmembers_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.guildmembers_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.guildmembers_seq OWNER TO postgres; + +-- +-- TOC entry 230 (class 1259 OID 25248) +-- Name: guildnews_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.guildnews_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.guildnews_seq OWNER TO postgres; + +-- +-- TOC entry 231 (class 1259 OID 25249) +-- Name: guilds; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.guilds ( + id bigint NOT NULL, + name character varying(50), + tag character varying(6), + description character varying(255), + motd character varying(255), + category integer, + language integer, + islfm boolean, + isinviterequired boolean, + rating integer, + creator_id bigint, + ranks bytea, + disbanded boolean +); + + +ALTER TABLE public.guilds OWNER TO postgres; + +-- +-- TOC entry 232 (class 1259 OID 25254) +-- Name: guilds_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.guilds_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.guilds_seq OWNER TO postgres; + +-- +-- TOC entry 233 (class 1259 OID 25255) +-- Name: hireling_data; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.hireling_data ( + id bigint NOT NULL, + dbtoon_id bigint, + class integer, + skill1snoid integer DEFAULT '-1'::integer NOT NULL, + skill2snoid integer DEFAULT '-1'::integer NOT NULL, + skill3snoid integer DEFAULT '-1'::integer NOT NULL, + skill4snoid integer DEFAULT '-1'::integer NOT NULL +); + + +ALTER TABLE public.hireling_data OWNER TO postgres; + +-- +-- TOC entry 234 (class 1259 OID 25262) +-- Name: hireling_data_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.hireling_data_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.hireling_data_seq OWNER TO postgres; + +-- +-- TOC entry 235 (class 1259 OID 25263) +-- Name: items; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.items ( + id bigint NOT NULL, + dbgameaccount_id bigint, + dbtoon_id bigint, + equipmentslot integer, + forsale boolean DEFAULT false NOT NULL, + hirelingid integer DEFAULT 0 NOT NULL, + locationx integer, + locationy integer, + ishardcore boolean DEFAULT false NOT NULL, + unidentified boolean DEFAULT false NOT NULL, + firstgem integer DEFAULT '-1'::integer NOT NULL, + secondgem integer DEFAULT '-1'::integer NOT NULL, + thirdgem integer DEFAULT '-1'::integer NOT NULL, + gbid integer, + version integer DEFAULT 1 NOT NULL, + count integer DEFAULT 1, + rareitemname bytea, + dyetype integer DEFAULT 0, + quality integer DEFAULT 1, + binding integer DEFAULT 0, + durability integer DEFAULT 0, + rating integer DEFAULT 0, + affixes character varying(255), + attributes character varying(2500), + transmoggbid integer DEFAULT '-1'::integer NOT NULL +); + + +ALTER TABLE public.items OWNER TO postgres; + +-- +-- TOC entry 236 (class 1259 OID 25283) +-- Name: items_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.items_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.items_seq OWNER TO postgres; + +-- +-- TOC entry 237 (class 1259 OID 25284) +-- Name: mail; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.mail ( + id bigint NOT NULL, + dbtoon_id bigint, + claimed boolean, + title character varying(255), + body character varying(255), + itemgbid integer +); + + +ALTER TABLE public.mail OWNER TO postgres; + +-- +-- TOC entry 238 (class 1259 OID 25289) +-- Name: mail_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.mail_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.mail_seq OWNER TO postgres; + +-- +-- TOC entry 239 (class 1259 OID 25290) +-- Name: quests; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.quests ( + id bigint NOT NULL, + dbtoon_id bigint, + questid integer, + iscompleted boolean DEFAULT false NOT NULL, + queststep integer +); + + +ALTER TABLE public.quests OWNER TO postgres; + +-- +-- TOC entry 240 (class 1259 OID 25294) +-- Name: quests_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.quests_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.quests_seq OWNER TO postgres; + +-- +-- TOC entry 241 (class 1259 OID 25295) +-- Name: reports; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.reports ( + id bigint NOT NULL, + type character varying(255), + dbgameaccount_id bigint, + dbtoon_id bigint, + sender_id bigint, + note character varying(255) +); + + +ALTER TABLE public.reports OWNER TO postgres; + +-- +-- TOC entry 242 (class 1259 OID 25300) +-- Name: reports_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.reports_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.reports_seq OWNER TO postgres; + +-- +-- TOC entry 243 (class 1259 OID 25301) +-- Name: skills; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.skills ( + id bigint NOT NULL, + dbtoon_id bigint, + rune0 integer, + skill0 integer, + rune1 integer, + skill1 integer, + rune2 integer, + skill2 integer, + rune3 integer, + skill3 integer, + rune4 integer, + skill4 integer, + rune5 integer, + skill5 integer, + passive0 integer, + passive1 integer, + passive2 integer, + passive3 integer DEFAULT '-1'::integer NOT NULL, + potiongbid integer DEFAULT '-1'::integer NOT NULL +); + + +ALTER TABLE public.skills OWNER TO postgres; + +-- +-- TOC entry 244 (class 1259 OID 25306) +-- Name: skills_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.skills_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.skills_seq OWNER TO postgres; + +-- +-- TOC entry 245 (class 1259 OID 25307) +-- Name: toons; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.toons ( + id bigint NOT NULL, + class character varying(255), + dbgameaccount_id bigint, + deleted boolean, + ishardcore boolean, + isseasoned boolean, + dead boolean, + timedeadharcode integer, + stoneofportal boolean, + createdseason integer, + experience integer, + paragonbonuses bytea, + pverating integer DEFAULT 0 NOT NULL, + chestsopened integer DEFAULT 0 NOT NULL, + eventscompleted integer DEFAULT 0 NOT NULL, + kills integer DEFAULT 0 NOT NULL, + deaths integer DEFAULT 0 NOT NULL, + eliteskilled integer DEFAULT 0 NOT NULL, + goldgained integer DEFAULT 0 NOT NULL, + activehireling integer, + currentact integer, + currentquestid integer, + currentqueststepid integer, + currentdifficulty integer, + flags character varying(255), + level smallint, + stats character varying(255) DEFAULT '0;0;0;0;0;0'::character varying NOT NULL, + name character varying(255), + timeplayed integer, + lore bytea, + archieved boolean DEFAULT false NOT NULL, + wingsactive integer DEFAULT '-1'::integer NOT NULL, + cosmetic1 integer, + cosmetic2 integer, + cosmetic3 integer, + cosmetic4 integer +); + + +ALTER TABLE public.toons OWNER TO postgres; + +-- +-- TOC entry 246 (class 1259 OID 25322) +-- Name: toons_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.toons_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.toons_seq OWNER TO postgres; + +-- +-- TOC entry 3257 (class 2604 OID 25323) +-- Name: DRLG_Container id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public."DRLG_Container" ALTER COLUMN id SET DEFAULT nextval('public."DRLG_Container_id_seq"'::regclass); + + +-- +-- TOC entry 3258 (class 2604 OID 25324) +-- Name: DRLG_Tile id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public."DRLG_Tile" ALTER COLUMN id SET DEFAULT nextval('public."DRLG_Tile_id_seq"'::regclass); + + +-- +-- TOC entry 3503 (class 0 OID 25184) +-- Dependencies: 209 +-- Data for Name: DRLG_Container; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +INSERT INTO public."DRLG_Container" VALUES (6, 452991, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (7, 452996, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (11, 288823, 200, NULL); +INSERT INTO public."DRLG_Container" VALUES (16, 331263, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (17, 360797, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (18, 452721, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (19, 452922, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (20, 452984, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (21, 452985, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (22, 452997, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (23, 452998, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (24, 288454, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (1, 0, 240, 50579); +INSERT INTO public."DRLG_Container" VALUES (2, 0, 240, 263494); +INSERT INTO public."DRLG_Container" VALUES (4, 0, 240, 82370); +INSERT INTO public."DRLG_Container" VALUES (5, 0, 240, 82371); +INSERT INTO public."DRLG_Container" VALUES (8, 0, 240, 72636); +INSERT INTO public."DRLG_Container" VALUES (9, 0, 240, 72637); +INSERT INTO public."DRLG_Container" VALUES (10, 0, 240, 154587); +INSERT INTO public."DRLG_Container" VALUES (12, 0, 240, 211471); +INSERT INTO public."DRLG_Container" VALUES (13, 0, 240, 161961); +INSERT INTO public."DRLG_Container" VALUES (14, 0, 240, 50582); +INSERT INTO public."DRLG_Container" VALUES (3, 0, 240, 230288); +INSERT INTO public."DRLG_Container" VALUES (15, 275921, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (25, 288843, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (26, 331389, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (27, 275960, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (28, 275946, 240, NULL); +INSERT INTO public."DRLG_Container" VALUES (29, 275926, 240, NULL); + + +-- +-- TOC entry 3505 (class 0 OID 25188) +-- Dependencies: 211 +-- Data for Name: DRLG_Tile; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +INSERT INTO public."DRLG_Tile" VALUES (1, 1, 0, 32990, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (2, 1, 1, 174633, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (3, 1, 1, 174643, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (4, 1, 1, 174657, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (5, 1, 1, 174663, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (6, 1, 2, 32939, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (7, 1, 2, 32941, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (8, 1, 2, 32951, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (9, 1, 2, 32952, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (10, 1, 2, 32954, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (11, 1, 2, 32955, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (12, 1, 2, 32958, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (13, 1, 2, 32960, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (14, 1, 2, 32961, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (15, 1, 2, 32963, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (16, 1, 2, 32979, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (17, 1, 2, 32981, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (18, 1, 2, 32982, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (19, 1, 2, 32983, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (20, 1, 2, 32985, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (21, 1, 2, 66589, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (22, 1, 2, 66919, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (23, 1, 2, 66925, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (24, 1, 2, 67021, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (25, 1, 2, 32986, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (26, 1, 2, 32987, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (27, 1, 3, 32938, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (28, 1, 3, 32969, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (29, 1, 3, 32970, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (30, 1, 3, 32989, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (31, 1, 3, 1886, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (32, 1, 3, 32943, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (33, 1, 3, 32971, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (34, 1, 3, 32991, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (35, 1, 3, 32999, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (41, 2, 0, 250881, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (42, 2, 0, 250882, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (43, 2, 0, 250883, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (44, 2, 0, 250884, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (45, 2, 1, 250881, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (46, 2, 1, 250882, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (47, 2, 1, 250883, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (48, 2, 1, 250884, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (49, 2, 2, 252804, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (50, 2, 2, 253156, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (51, 2, 2, 289062, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (52, 2, 2, 289135, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (53, 2, 2, 289146, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (54, 2, 2, 253322, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (55, 2, 2, 253395, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (56, 2, 2, 242155, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (57, 2, 2, 242190, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (58, 2, 2, 242272, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (59, 2, 2, 242295, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (60, 2, 2, 242312, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (61, 2, 2, 242326, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (62, 2, 2, 242847, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (63, 2, 2, 242678, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (64, 2, 2, 242711, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (65, 2, 2, 242801, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (66, 2, 2, 242881, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (67, 2, 2, 242935, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (68, 2, 2, 243101, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (69, 2, 2, 243923, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (70, 2, 2, 243990, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (71, 2, 2, 244026, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (72, 2, 2, 244152, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (73, 2, 2, 244271, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (74, 2, 2, 244575, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (75, 2, 2, 244617, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (76, 2, 2, 244655, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (77, 2, 2, 244673, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (78, 2, 2, 244706, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (79, 2, 2, 244722, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (80, 2, 2, 244743, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (81, 2, 2, 244800, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (82, 2, 2, 245024, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (83, 2, 2, 245078, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (84, 2, 2, 245132, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (85, 2, 2, 245192, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (86, 2, 2, 245204, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (87, 2, 2, 245365, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (88, 2, 2, 245507, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (89, 2, 2, 245644, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (90, 2, 3, 244921, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (91, 2, 3, 243005, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (92, 2, 3, 243895, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (93, 2, 3, 243905, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (94, 2, 3, 243954, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (95, 2, 3, 243970, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (96, 2, 3, 244132, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (97, 2, 3, 244230, 263493, -1, 315939); +INSERT INTO public."DRLG_Tile" VALUES (98, 4, 0, 478085, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (99, 4, 0, 77876, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (100, 4, 1, 478079, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (101, 4, 1, 33034, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (102, 4, 1, 33016, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (103, 4, 1, 33041, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (104, 4, 2, 33011, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (105, 4, 2, 33024, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (106, 4, 2, 33025, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (107, 4, 2, 33026, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (108, 4, 2, 33027, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (109, 4, 2, 33029, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (110, 4, 2, 33030, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (111, 4, 2, 33031, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (112, 4, 2, 33037, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (113, 4, 2, 33038, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (114, 4, 3, 33044, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (115, 4, 3, 33039, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (116, 4, 3, 33032, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (117, 4, 3, 33014, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (118, 5, 0, 33040, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (119, 5, 0, 33033, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (120, 5, 1, 33039, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (121, 5, 1, 33044, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (122, 5, 1, 33046, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (123, 5, 1, 33032, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (124, 5, 2, 33011, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (125, 5, 2, 33024, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (126, 5, 2, 33025, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (127, 5, 2, 33026, 82372, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (128, 5, 2, 33027, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (129, 5, 2, 33029, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (130, 5, 2, 33030, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (131, 5, 2, 33031, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (132, 5, 2, 33037, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (133, 5, 2, 33038, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (136, 5, 2, 478081, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (137, 5, 2, 478083, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (138, 5, 3, 478082, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (139, 5, 3, 478084, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (140, 5, 3, 33032, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (141, 5, 3, 33039, 82373, -1, 86469); +INSERT INTO public."DRLG_Tile" VALUES (142, 6, 0, 456189, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (143, 6, 0, 456192, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (144, 6, 0, 456195, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (145, 6, 0, 456197, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (146, 6, 1, 456202, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (147, 6, 1, 456205, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (148, 6, 1, 456208, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (149, 6, 1, 456211, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (150, 6, 2, 456219, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (151, 6, 2, 456222, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (152, 6, 2, 456228, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (153, 6, 2, 456231, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (154, 6, 2, 456233, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (155, 6, 2, 456236, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (156, 6, 2, 456239, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (157, 6, 2, 456242, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (158, 6, 2, 456245, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (159, 6, 2, 456247, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (160, 6, 2, 456250, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (161, 6, 2, 456252, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (162, 6, 2, 456255, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (163, 6, 2, 456258, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (164, 6, 2, 456263, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (165, 6, 2, 456269, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (166, 6, 2, 456273, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (167, 6, 2, 456276, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (168, 6, 2, 456279, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (169, 6, 2, 456282, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (170, 6, 2, 456285, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (171, 6, 2, 456294, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (172, 6, 2, 456295, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (173, 6, 3, 456216, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (174, 6, 3, 456225, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (175, 6, 3, 456266, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (176, 6, 3, 456288, 452992, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (177, 7, 0, 456189, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (178, 7, 0, 456192, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (179, 7, 0, 456195, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (180, 7, 0, 456197, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (181, 7, 1, 456202, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (182, 7, 1, 456205, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (183, 7, 1, 456208, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (184, 7, 1, 456211, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (185, 7, 2, 456219, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (186, 7, 2, 456222, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (187, 7, 2, 456228, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (188, 7, 2, 456231, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (189, 7, 2, 456233, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (190, 7, 2, 456236, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (191, 7, 2, 456239, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (192, 7, 2, 456242, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (193, 7, 2, 456245, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (194, 7, 2, 456247, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (195, 7, 2, 456250, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (196, 7, 2, 456252, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (197, 7, 2, 456255, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (198, 7, 2, 456258, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (199, 7, 2, 456263, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (200, 7, 2, 456269, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (201, 7, 2, 456273, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (202, 7, 2, 456276, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (203, 7, 2, 456279, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (204, 7, 2, 456282, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (205, 7, 2, 456285, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (206, 7, 2, 456294, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (207, 7, 2, 456295, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (208, 7, 3, 456216, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (209, 7, 3, 456225, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (210, 7, 3, 456266, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (211, 7, 3, 456288, 452993, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (217, 8, 0, 33094, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (218, 8, 0, 33057, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (220, 8, 0, 33099, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (221, 8, 0, 61489, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (222, 8, 0, 61650, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (223, 8, 0, 61567, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (224, 8, 1, 84766, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (225, 8, 1, 84775, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (226, 8, 1, 84784, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (227, 8, 1, 84787, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (228, 8, 2, 33051, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (229, 8, 2, 33054, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (230, 8, 2, 33066, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (231, 8, 2, 33068, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (232, 8, 2, 33070, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (235, 8, 2, 33073, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (236, 8, 2, 33075, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (237, 8, 2, 33076, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (238, 8, 2, 33077, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (239, 8, 2, 33078, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (240, 8, 2, 33086, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (241, 8, 2, 33087, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (242, 8, 2, 33091, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (243, 8, 2, 33092, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (244, 8, 2, 1890, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (245, 8, 3, 61237, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (246, 8, 3, 61403, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (247, 8, 3, 61428, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (248, 8, 3, 61449, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (274, 1, 4, 32936, 19780, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (275, 12, 0, 211486, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (276, 12, 0, 211488, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (277, 12, 0, 211490, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (278, 12, 0, 211492, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (279, 12, 1, 343946, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (280, 12, 1, 343947, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (281, 12, 1, 343948, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (282, 12, 1, 343949, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (283, 12, 2, 209181, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (284, 12, 2, 209225, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (285, 12, 2, 204737, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (286, 12, 2, 204745, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (287, 12, 2, 204755, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (288, 12, 2, 204765, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (289, 12, 2, 204775, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (290, 12, 3, 204624, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (291, 12, 3, 204788, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (292, 12, 3, 204804, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (252, 11, 0, 31100, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (254, 11, 1, 31102, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (256, 11, 1, 31083, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (257, 11, 1, 31096, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (258, 11, 2, 31079, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (259, 11, 2, 31085, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (260, 11, 2, 31086, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (261, 11, 2, 31087, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (262, 11, 2, 31088, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (263, 11, 2, 31089, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (264, 11, 2, 31090, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (265, 11, 2, 31091, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (266, 11, 2, 31092, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (267, 11, 2, 31097, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (269, 11, 3, 31080, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (270, 11, 3, 31093, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (272, 11, 3, 31103, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (293, 12, 3, 204814, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (294, 12, 4, 204614, 211479, -1, 206287); +INSERT INTO public."DRLG_Tile" VALUES (295, 13, 4, 154775, 161964, -1, 2809); +INSERT INTO public."DRLG_Tile" VALUES (296, 13, 3, 132203, 161964, -1, 2809); +INSERT INTO public."DRLG_Tile" VALUES (297, 13, 0, 132218, 161964, -1, 2809); +INSERT INTO public."DRLG_Tile" VALUES (298, 13, 3, 132263, 161964, -1, 2809); +INSERT INTO public."DRLG_Tile" VALUES (299, 13, 3, 132293, 161964, -1, 2809); +INSERT INTO public."DRLG_Tile" VALUES (300, 13, 2, 131902, 161964, -1, 2809); +INSERT INTO public."DRLG_Tile" VALUES (301, 15, 4, 32936, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (302, 15, 0, 32940, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (303, 15, 1, 32948, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (304, 15, 1, 32997, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (305, 15, 1, 33002, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (306, -1, 1, -1, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (307, 15, 3, 32999, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (308, 15, 3, 32971, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (309, 15, 3, 32991, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (310, 15, 3, 32943, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (311, 15, 2, 32981, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (312, 15, 2, 32985, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (313, 15, 2, 32982, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (314, 15, 2, 32983, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (315, 15, 2, 32965, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (316, 15, 2, 32967, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (317, 15, 2, 32951, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (318, 15, 2, 32952, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (319, 15, 2, 32939, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (320, 15, 2, 32941, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (321, 15, 2, 32961, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (322, 15, 2, 32963, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (323, 15, 2, 32954, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (324, 15, 2, 32958, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (325, 15, 2, 32979, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (326, 15, 2, 32960, 19785, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (327, 14, 4, 32936, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (328, 14, 0, 32944, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (329, 14, 0, 32972, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (330, 14, 0, 32992, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (331, 14, 0, 33000, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (332, 14, 1, 32976, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (333, 14, 1, 33001, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (334, 14, 1, 32946, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (335, 14, 3, 32999, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (336, 14, 3, 32971, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (337, 14, 3, 32991, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (338, 14, 3, 32943, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (339, 14, 2, 32981, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (340, 14, 2, 32985, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (341, 14, 2, 32982, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (342, 14, 2, 32983, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (343, 14, 2, 32965, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (344, 14, 2, 32967, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (345, 14, 2, 32951, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (346, 14, 2, 32952, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (347, 14, 2, 32939, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (348, 14, 2, 32941, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (349, 14, 2, 32961, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (350, 14, 2, 32963, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (351, 14, 2, 32954, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (352, 14, 2, 32958, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (353, 14, 2, 32979, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (354, 14, 2, 32960, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (355, 14, 2, 32984, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (356, 14, 2, 66589, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (357, 14, 2, 66919, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (358, 14, 2, 66925, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (359, 14, 2, 67021, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (360, 14, 2, 1883, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (361, 14, 2, 1884, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (362, 14, 2, 1885, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (363, 14, 1, 32993, 19783, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (445, 18, 4, 32936, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (446, 18, 0, 32944, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (447, 18, 0, 32972, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (448, 18, 0, 32992, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (449, 18, 0, 33000, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (450, 18, 1, 32976, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (451, 18, 1, 33001, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (452, 18, 1, 32946, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (414, 17, 0, 270859, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (415, 17, 0, 270960, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (417, 17, 1, 271019, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (418, 17, 1, 270973, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (419, 17, 1, 270873, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (420, 17, 1, 270931, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (421, 17, 3, 269281, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (422, 17, 3, 269240, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (423, 17, 3, 269253, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (424, 17, 3, 269271, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (425, 17, 2, 269081, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (411, 16, 2, 252804, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (365, 16, 0, 337235, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (366, 16, 0, 337236, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (368, 16, 0, 337238, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (369, 16, 1, 250892, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (371, 16, 1, 250894, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (372, 16, 1, 250895, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (373, 16, 3, 243005, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (374, 16, 3, 243895, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (410, 16, 2, 244271, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (409, 16, 2, 244026, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (408, 16, 2, 245204, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (407, 16, 2, 244800, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (406, 16, 2, 242155, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (405, 16, 2, 289062, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (404, 16, 2, 245132, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (403, 16, 2, 245024, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (402, 16, 2, 245078, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (401, 16, 2, 242295, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (398, 16, 2, 244152, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (397, 16, 2, 243101, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (396, 16, 2, 242801, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (375, 16, 3, 243905, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (376, 16, 3, 243954, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (377, 16, 3, 244132, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (378, 16, 3, 244230, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (379, 16, 2, 242678, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (380, 16, 2, 244673, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (381, 16, 2, 244743, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (383, 16, 2, 243990, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (384, 16, 2, 253156, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (385, 16, 2, 253322, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (386, 16, 2, 253395, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (388, 16, 2, 242312, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (389, 16, 2, 245192, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (390, 16, 2, 244617, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (391, 16, 2, 242272, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (392, 16, 2, 245365, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (393, 16, 2, 245507, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (394, 16, 2, 245644, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (395, 16, 2, 242190, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (453, 18, 3, 32999, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (454, 18, 3, 32971, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (455, 18, 3, 32991, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (456, 18, 3, 32943, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (457, 18, 2, 32981, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (458, 18, 2, 32985, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (459, 18, 2, 32982, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (460, 18, 2, 32983, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (461, 18, 2, 32965, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (462, 18, 2, 32967, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (463, 18, 2, 32951, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (464, 18, 2, 32952, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (465, 18, 2, 32939, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (466, 18, 2, 32941, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (467, 18, 2, 32961, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (468, 18, 2, 32963, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (469, 18, 2, 32954, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (470, 18, 2, 32958, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (471, 18, 2, 32979, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (472, 18, 2, 32960, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (473, 18, 2, 32984, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (474, 18, 2, 66589, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (475, 18, 2, 66919, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (476, 18, 2, 66925, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (477, 18, 2, 67021, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (478, 18, 2, 1883, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (479, 18, 2, 1884, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (480, 18, 2, 1885, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (481, 18, 1, 32993, 452986, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (482, 19, 4, 32936, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (483, 19, 0, 32944, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (484, 19, 0, 32972, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (485, 19, 0, 32992, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (486, 19, 0, 33000, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (487, 19, 1, 32976, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (488, 19, 1, 33001, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (489, 19, 1, 32946, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (490, 19, 3, 32999, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (491, 19, 3, 32971, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (492, 19, 3, 32991, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (493, 19, 3, 32943, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (494, 19, 2, 32981, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (495, 19, 2, 32985, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (496, 19, 2, 32982, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (497, 19, 2, 32983, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (498, 19, 2, 32965, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (499, 19, 2, 32967, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (500, 19, 2, 32951, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (501, 19, 2, 32952, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (502, 19, 2, 32939, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (503, 19, 2, 32941, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (504, 19, 2, 32961, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (505, 19, 2, 32963, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (506, 19, 2, 32954, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (507, 19, 2, 32958, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (508, 19, 2, 32979, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (509, 19, 2, 32960, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (510, 19, 2, 32984, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (511, 19, 2, 66589, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (512, 19, 2, 66919, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (513, 19, 2, 66925, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (514, 19, 2, 67021, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (515, 19, 2, 1883, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (516, 19, 2, 1884, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (517, 19, 2, 1885, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (518, 19, 1, 32993, 452988, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (519, 20, 0, 32944, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (520, 20, 0, 32972, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (521, 20, 0, 32992, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (522, 20, 0, 33000, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (523, 20, 1, 32976, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (524, 20, 1, 33001, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (525, 20, 1, 32946, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (526, 20, 3, 32999, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (527, 20, 3, 32971, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (528, 20, 3, 32991, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (529, 20, 3, 32943, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (530, 20, 2, 32981, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (531, 20, 2, 32985, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (532, 20, 2, 32982, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (533, 20, 2, 32983, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (534, 20, 2, 32965, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (535, 20, 2, 32967, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (536, 20, 2, 32951, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (537, 20, 2, 32952, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (538, 20, 2, 32939, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (539, 20, 2, 32941, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (540, 20, 2, 32961, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (541, 20, 2, 32963, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (542, 20, 2, 32954, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (543, 20, 2, 32958, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (544, 20, 2, 32979, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (545, 20, 2, 32960, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (546, 20, 2, 32984, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (547, 20, 2, 66589, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (548, 20, 2, 66919, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (549, 20, 2, 66925, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (550, 20, 2, 67021, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (551, 20, 2, 1883, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (552, 20, 2, 1884, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (553, 20, 2, 1885, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (554, 20, 1, 32993, 452989, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (555, 21, 0, 32944, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (556, 21, 0, 32972, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (557, 21, 0, 32992, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (558, 21, 0, 33000, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (559, 21, 1, 32976, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (560, 21, 1, 33001, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (561, 21, 1, 32946, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (562, 21, 3, 32999, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (563, 21, 3, 32971, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (564, 21, 3, 32991, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (565, 21, 3, 32943, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (566, 21, 2, 32981, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (567, 21, 2, 32985, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (568, 21, 2, 32982, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (569, 21, 2, 32983, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (570, 21, 2, 32965, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (571, 21, 2, 32967, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (572, 21, 2, 32951, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (428, 17, 2, 269427, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (429, 17, 2, 268554, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (442, 17, 2, 271661, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (440, 17, 2, 271842, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (439, 17, 2, 268682, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (438, 17, 2, 271696, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (437, 17, 2, 269047, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (436, 17, 2, 271571, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (435, 17, 2, 268943, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (434, 17, 2, 271760, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (433, 17, 2, 269204, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (430, 17, 2, 272180, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (431, 17, 2, 268617, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (432, 17, 2, 271995, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (573, 21, 2, 32952, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (574, 21, 2, 32939, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (575, 21, 2, 32941, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (576, 21, 2, 32961, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (577, 21, 2, 32963, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (578, 21, 2, 32954, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (579, 21, 2, 32958, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (580, 21, 2, 32979, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (581, 21, 2, 32960, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (582, 21, 2, 32984, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (583, 21, 2, 66589, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (584, 21, 2, 66919, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (585, 21, 2, 66925, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (586, 21, 2, 67021, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (587, 21, 2, 1883, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (588, 21, 2, 1884, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (589, 21, 2, 1885, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (590, 21, 1, 32993, 452990, -1, 50535); +INSERT INTO public."DRLG_Tile" VALUES (591, 22, 0, 456189, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (592, 22, 0, 456192, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (593, 22, 0, 456195, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (594, 22, 0, 456197, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (595, 22, 1, 456202, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (596, 22, 1, 456205, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (597, 22, 1, 456208, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (598, 22, 1, 456211, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (599, 22, 2, 456219, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (600, 22, 2, 456222, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (601, 22, 2, 456228, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (602, 22, 2, 456231, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (603, 22, 2, 456233, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (604, 22, 2, 456236, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (605, 22, 2, 456239, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (606, 22, 2, 456242, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (607, 22, 2, 456245, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (608, 22, 2, 456247, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (609, 22, 2, 456250, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (610, 22, 2, 456252, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (611, 22, 2, 456255, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (612, 22, 2, 456258, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (613, 22, 2, 456263, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (614, 22, 2, 456269, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (615, 22, 2, 456273, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (616, 22, 2, 456276, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (617, 22, 2, 456279, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (618, 22, 2, 456282, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (619, 22, 2, 456285, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (620, 22, 2, 456294, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (621, 22, 2, 456295, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (622, 22, 3, 456216, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (623, 22, 3, 456225, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (624, 22, 3, 456266, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (625, 22, 3, 456288, 452994, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (626, 23, 0, 456189, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (627, 23, 0, 456192, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (628, 23, 0, 456195, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (629, 23, 0, 456197, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (630, 23, 1, 456202, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (631, 23, 1, 456205, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (632, 23, 1, 456208, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (633, 23, 1, 456211, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (634, 23, 2, 456219, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (635, 23, 2, 456222, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (636, 23, 2, 456228, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (637, 23, 2, 456231, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (638, 23, 2, 456233, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (639, 23, 2, 456236, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (640, 23, 2, 456239, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (641, 23, 2, 456242, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (642, 23, 2, 456245, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (643, 23, 2, 456247, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (644, 23, 2, 456250, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (645, 23, 2, 456252, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (646, 23, 2, 456255, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (647, 23, 2, 456258, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (648, 23, 2, 456263, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (649, 23, 2, 456269, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (650, 23, 2, 456273, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (651, 23, 2, 456276, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (652, 23, 2, 456279, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (653, 23, 2, 456282, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (654, 23, 2, 456285, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (655, 23, 2, 456294, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (656, 23, 2, 456295, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (657, 23, 3, 456216, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (658, 23, 3, 456225, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (659, 23, 3, 456266, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (660, 23, 3, 456288, 452995, -1, 453221); +INSERT INTO public."DRLG_Tile" VALUES (661, 10, 4, 33060, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (662, 10, 0, 33094, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (663, 10, 0, 33099, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (664, -1, 0, 33057, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (665, -1, 0, 61489, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (666, -1, 0, 61567, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (667, -1, 0, 61650, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (669, 10, 1, 84766, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (670, 10, 1, 84775, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (671, 10, 1, 84784, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (672, 10, 1, 84787, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (673, 10, 2, 1890, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (674, 10, 2, 33066, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (675, 10, 2, 33068, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (676, 10, 2, 33070, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (677, 10, 2, 33071, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (678, 10, 2, 33072, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (679, 10, 2, 33073, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (680, 10, 2, 33075, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (681, 10, 2, 33076, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (682, 10, 2, 33077, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (683, 10, 2, 33078, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (684, 10, 2, 33086, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (685, 10, 2, 33087, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (686, 10, 2, 33091, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (687, 10, 2, 33092, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (688, 10, 3, 61237, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (689, 10, 3, 61403, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (690, 10, 3, 61428, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (691, 10, 3, 61449, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (692, 24, 0, 151979, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (693, 24, 0, 154056, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (694, 24, 0, 154731, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (695, 24, 0, 154821, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (696, 24, 1, 155325, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (697, 24, 1, 154066, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (698, 24, 1, 156637, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (699, 24, 1, 156649, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (700, 24, 2, 221307, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (701, 24, 2, 151143, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (702, 24, 2, 151319, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (703, 24, 2, 151698, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (704, 24, 2, 133974, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (705, 24, 2, 152038, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (706, 24, 2, 152562, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (707, 24, 2, 152610, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (708, 24, 2, 152935, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (709, 24, 2, 153112, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (710, 24, 2, 153250, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (711, 24, 2, 153287, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (712, 24, 2, 154118, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (713, 24, 2, 154189, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (714, 24, 2, 154223, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (715, 24, 2, 154639, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (716, 24, 2, 460991, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (717, 24, 2, 464560, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (718, 24, 3, 151655, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (719, 24, 3, 154038, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (720, 24, 3, 154687, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (721, 24, 3, 154791, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (722, 24, 3, 460986, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (723, 24, 4, 154952, 288482, -1, 214225); +INSERT INTO public."DRLG_Tile" VALUES (724, 9, 0, 33094, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (725, 9, 0, 33057, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (726, 9, 0, 33099, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (727, 9, 0, 61489, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (728, 9, 0, 61650, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (729, 9, 0, 61567, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (730, 9, 1, 84766, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (731, 9, 1, 84775, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (732, 9, 1, 84784, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (733, 9, 1, 84787, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (734, 9, 2, 33051, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (735, 9, 2, 33054, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (736, 9, 2, 33066, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (737, 9, 2, 33068, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (738, 9, 2, 33070, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (739, 9, 2, 33073, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (740, 9, 2, 33075, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (741, 9, 2, 33076, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (742, 9, 2, 33077, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (743, 9, 2, 33078, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (744, 9, 2, 33086, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (745, 9, 2, 33087, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (746, 9, 2, 33091, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (747, 9, 2, 33092, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (748, 9, 2, 1890, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (749, 9, 3, 61237, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (750, 9, 3, 61403, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (751, 9, 3, 61428, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (752, 9, 3, 61449, 154588, -1, 50542); +INSERT INTO public."DRLG_Tile" VALUES (412, 17, 4, 269728, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (413, 17, 0, 270898, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (416, 17, 0, 271005, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (426, 17, 2, 271684, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (427, 17, 2, 269063, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (444, 17, 2, 271724, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (443, 17, 2, 269227, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (441, 17, 2, 269183, 333758, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (364, 16, 4, 313270, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (367, 16, 0, 337237, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (370, 16, 1, 250893, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (400, 16, 2, 242711, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (399, 16, 2, 244575, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (382, 16, 2, 242326, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (762, 26, 2, 292833, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (763, 26, 2, 292969, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (764, 26, 2, 271073, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (765, 26, 2, 293035, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (766, 26, 2, 293233, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (767, 26, 2, 293329, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (768, 26, 2, 294284, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (387, 16, 2, 289135, 331264, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (806, 28, 3, 61237, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (789, 27, 2, 188872, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (790, 27, 2, 188884, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (791, 27, 2, 188896, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (792, 27, 2, 188909, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (793, 27, 2, 188926, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (794, 27, 2, 188940, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (777, 27, 4, 188860, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (769, 26, 3, 288966, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (770, 26, 3, 289231, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (771, 26, 3, 292911, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (761, 26, 4, 288276, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (753, 26, 0, 293459, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (754, 26, 0, 293469, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (755, 26, 0, 293479, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (756, 26, 0, 293500, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (757, 26, 1, 293489, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (758, 26, 1, 293512, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (759, 26, 1, 293522, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (760, 26, 1, 293540, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (797, 27, 2, 189028, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (782, 27, 3, 188842, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (773, 27, 0, 188973, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (774, 27, 0, 189120, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (775, 27, 0, 189152, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (772, 26, 3, 292957, 352719, -1, 461364); +INSERT INTO public."DRLG_Tile" VALUES (250, 11, 0, 31081, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (251, 11, 0, 31094, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (253, 11, 0, 31105, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (255, 11, 1, 31107, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (268, 11, 2, 31098, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (271, 11, 3, 31099, 312607, -1, -1); +INSERT INTO public."DRLG_Tile" VALUES (776, 27, 0, 188852, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (778, 27, 1, 189312, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (779, 27, 1, 189323, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (780, 27, 1, 189324, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (781, 27, 1, 189325, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (783, 27, 3, 188957, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (784, 27, 3, 189089, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (785, 27, 3, 189137, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (786, 27, 2, 188753, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (787, 27, 2, 189322, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (795, 27, 2, 189003, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (796, 27, 2, 189016, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (804, 28, 1, 175020, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (799, 28, 0, 33082, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (805, 28, 1, 175021, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (788, 27, 2, 188826, 276230, -1, 188757); +INSERT INTO public."DRLG_Tile" VALUES (809, 28, 3, 61449, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (800, 28, 0, 33094, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (807, 28, 3, 61403, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (811, 28, 2, 33071, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (813, 28, 2, 33073, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (808, 28, 3, 61428, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (812, 28, 2, 33066, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (814, 28, 2, 33068, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (815, 28, 2, 33070, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (816, 28, 2, 33051, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (818, 28, 2, 33075, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (819, 28, 2, 33076, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (820, 28, 2, 33077, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (798, 28, 0, 33057, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (801, 28, 0, 33099, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (802, 28, 1, 175016, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (846, 29, 2, 153112, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (847, 29, 2, 153250, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (848, 29, 2, 153287, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (849, 29, 2, 154118, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (850, 29, 2, 154189, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (851, 29, 2, 154223, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (852, 29, 2, 154639, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (853, 29, 2, 151698, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (854, 29, 3, 154791, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (855, 29, 3, 154687, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (856, 29, 3, 154038, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (857, 29, 3, 151655, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (858, 29, 4, 154952, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (803, 28, 1, 175018, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (810, 28, 4, 33060, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (817, 28, 2, 33054, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (821, 28, 2, 33078, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (822, 28, 2, 33068, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (823, 28, 2, 33087, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (824, 28, 2, 33091, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (825, 28, 2, 33092, 276150, -1, 339913); +INSERT INTO public."DRLG_Tile" VALUES (859, NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO public."DRLG_Tile" VALUES (826, 29, 0, 151979, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (827, 29, 0, 154056, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (828, 29, 0, 154731, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (829, 29, 0, 154821, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (830, 29, 1, 261453, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (831, 29, 1, 261454, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (832, 29, 1, 261455, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (833, 29, 1, 261456, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (834, 29, 2, 220797, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (835, 29, 2, 221307, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (836, 29, 2, 151143, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (837, 29, 2, 151319, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (860, NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO public."DRLG_Tile" VALUES (861, NULL, NULL, NULL, NULL, NULL, NULL); +INSERT INTO public."DRLG_Tile" VALUES (838, 29, 2, 133974, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (839, 29, 2, 152038, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (840, 29, 2, 223742, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (841, 29, 2, 223766, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (842, 29, 2, 152562, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (843, 29, 2, 152610, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (844, 29, 2, 152935, 275929, -1, 339488); +INSERT INTO public."DRLG_Tile" VALUES (845, 29, 2, 224644, 275929, -1, 339488); + + +-- +-- TOC entry 3507 (class 0 OID 25192) +-- Dependencies: 213 +-- Data for Name: account_relations; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3509 (class 0 OID 25197) +-- Dependencies: 215 +-- Data for Name: accounts; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3511 (class 0 OID 25207) +-- Dependencies: 217 +-- Data for Name: achievements; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3513 (class 0 OID 25215) +-- Dependencies: 219 +-- Data for Name: collection_editions; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3515 (class 0 OID 25221) +-- Dependencies: 221 +-- Data for Name: craft_data; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3517 (class 0 OID 25227) +-- Dependencies: 223 +-- Data for Name: game_accounts; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3519 (class 0 OID 25235) +-- Dependencies: 225 +-- Data for Name: global_params; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3521 (class 0 OID 25239) +-- Dependencies: 227 +-- Data for Name: guild_members; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3522 (class 0 OID 25242) +-- Dependencies: 228 +-- Data for Name: guild_news; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3525 (class 0 OID 25249) +-- Dependencies: 231 +-- Data for Name: guilds; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3527 (class 0 OID 25255) +-- Dependencies: 233 +-- Data for Name: hireling_data; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3529 (class 0 OID 25263) +-- Dependencies: 235 +-- Data for Name: items; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3531 (class 0 OID 25284) +-- Dependencies: 237 +-- Data for Name: mail; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3533 (class 0 OID 25290) +-- Dependencies: 239 +-- Data for Name: quests; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3535 (class 0 OID 25295) +-- Dependencies: 241 +-- Data for Name: reports; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3537 (class 0 OID 25301) +-- Dependencies: 243 +-- Data for Name: skills; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3539 (class 0 OID 25307) +-- Dependencies: 245 +-- Data for Name: toons; Type: TABLE DATA; Schema: public; Owner: postgres +-- + + + +-- +-- TOC entry 3550 (class 0 OID 0) +-- Dependencies: 210 +-- Name: DRLG_Container_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public."DRLG_Container_id_seq"', 1, false); + + +-- +-- TOC entry 3551 (class 0 OID 0) +-- Dependencies: 212 +-- Name: DRLG_Tile_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public."DRLG_Tile_id_seq"', 1, false); + + +-- +-- TOC entry 3552 (class 0 OID 0) +-- Dependencies: 214 +-- Name: account_relations_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.account_relations_seq', 1, false); + + +-- +-- TOC entry 3553 (class 0 OID 0) +-- Dependencies: 216 +-- Name: accounts_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.accounts_seq', 1, false); + + +-- +-- TOC entry 3554 (class 0 OID 0) +-- Dependencies: 218 +-- Name: achievements_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.achievements_seq', 1, false); + + +-- +-- TOC entry 3555 (class 0 OID 0) +-- Dependencies: 220 +-- Name: collection_editions_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.collection_editions_seq', 1, false); + + +-- +-- TOC entry 3556 (class 0 OID 0) +-- Dependencies: 222 +-- Name: craft_data_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.craft_data_seq', 1, false); + + +-- +-- TOC entry 3557 (class 0 OID 0) +-- Dependencies: 224 +-- Name: game_accounts_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.game_accounts_seq', 1, false); + + +-- +-- TOC entry 3558 (class 0 OID 0) +-- Dependencies: 226 +-- Name: global_params_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.global_params_seq', 1, false); + + +-- +-- TOC entry 3559 (class 0 OID 0) +-- Dependencies: 229 +-- Name: guildmembers_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.guildmembers_seq', 1, false); + + +-- +-- TOC entry 3560 (class 0 OID 0) +-- Dependencies: 230 +-- Name: guildnews_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.guildnews_seq', 1, false); + + +-- +-- TOC entry 3561 (class 0 OID 0) +-- Dependencies: 232 +-- Name: guilds_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.guilds_seq', 1, false); + + +-- +-- TOC entry 3562 (class 0 OID 0) +-- Dependencies: 234 +-- Name: hireling_data_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.hireling_data_seq', 1, false); + + +-- +-- TOC entry 3563 (class 0 OID 0) +-- Dependencies: 236 +-- Name: items_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.items_seq', 1, false); + + +-- +-- TOC entry 3564 (class 0 OID 0) +-- Dependencies: 238 +-- Name: mail_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.mail_seq', 1, false); + + +-- +-- TOC entry 3565 (class 0 OID 0) +-- Dependencies: 240 +-- Name: quests_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.quests_seq', 1, false); + + +-- +-- TOC entry 3566 (class 0 OID 0) +-- Dependencies: 242 +-- Name: reports_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.reports_seq', 1, false); + + +-- +-- TOC entry 3567 (class 0 OID 0) +-- Dependencies: 244 +-- Name: skills_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.skills_seq', 1, false); + + +-- +-- TOC entry 3568 (class 0 OID 0) +-- Dependencies: 246 +-- Name: toons_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.toons_seq', 1, false); + + +-- +-- TOC entry 3303 (class 2606 OID 25326) +-- Name: DRLG_Container DRLG_Container_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public."DRLG_Container" + ADD CONSTRAINT "DRLG_Container_pkey" PRIMARY KEY (id); + + +-- +-- TOC entry 3305 (class 2606 OID 25328) +-- Name: DRLG_Tile DRLG_Tile_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public."DRLG_Tile" + ADD CONSTRAINT "DRLG_Tile_pkey" PRIMARY KEY (id); + + +-- +-- TOC entry 3307 (class 2606 OID 25330) +-- Name: account_relations account_relations_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.account_relations + ADD CONSTRAINT account_relations_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3309 (class 2606 OID 25332) +-- Name: accounts accounts_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.accounts + ADD CONSTRAINT accounts_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3311 (class 2606 OID 25334) +-- Name: achievements achievements_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.achievements + ADD CONSTRAINT achievements_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3313 (class 2606 OID 25336) +-- Name: collection_editions collection_editions_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.collection_editions + ADD CONSTRAINT collection_editions_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3315 (class 2606 OID 25338) +-- Name: craft_data craft_data_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.craft_data + ADD CONSTRAINT craft_data_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3317 (class 2606 OID 25340) +-- Name: game_accounts game_accounts_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.game_accounts + ADD CONSTRAINT game_accounts_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3319 (class 2606 OID 25342) +-- Name: global_params global_params_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.global_params + ADD CONSTRAINT global_params_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3321 (class 2606 OID 25344) +-- Name: guild_members guild_members_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.guild_members + ADD CONSTRAINT guild_members_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3323 (class 2606 OID 25346) +-- Name: guild_news guild_news_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.guild_news + ADD CONSTRAINT guild_news_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3325 (class 2606 OID 25348) +-- Name: guilds guilds_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.guilds + ADD CONSTRAINT guilds_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3327 (class 2606 OID 25350) +-- Name: hireling_data hireling_data_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.hireling_data + ADD CONSTRAINT hireling_data_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3329 (class 2606 OID 25352) +-- Name: items items_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.items + ADD CONSTRAINT items_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3331 (class 2606 OID 25354) +-- Name: mail mail_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.mail + ADD CONSTRAINT mail_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3333 (class 2606 OID 25356) +-- Name: quests quests_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.quests + ADD CONSTRAINT quests_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3335 (class 2606 OID 25358) +-- Name: reports reports_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.reports + ADD CONSTRAINT reports_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3337 (class 2606 OID 25360) +-- Name: skills skills_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.skills + ADD CONSTRAINT skills_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3339 (class 2606 OID 25362) +-- Name: toons toons_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.toons + ADD CONSTRAINT toons_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 3362 (class 2606 OID 25363) +-- Name: skills fk_13ada7d3; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.skills + ADD CONSTRAINT fk_13ada7d3 FOREIGN KEY (dbtoon_id) REFERENCES public.toons(id); + + +-- +-- TOC entry 3343 (class 2606 OID 25368) +-- Name: achievements fk_18070981; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.achievements + ADD CONSTRAINT fk_18070981 FOREIGN KEY (dbgameaccount_id) REFERENCES public.game_accounts(id); + + +-- +-- TOC entry 3359 (class 2606 OID 25373) +-- Name: reports fk_1e0edf25; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.reports + ADD CONSTRAINT fk_1e0edf25 FOREIGN KEY (sender_id) REFERENCES public.game_accounts(id); + + +-- +-- TOC entry 3360 (class 2606 OID 25378) +-- Name: reports fk_2e7cba8c; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.reports + ADD CONSTRAINT fk_2e7cba8c FOREIGN KEY (dbgameaccount_id) REFERENCES public.game_accounts(id); + + +-- +-- TOC entry 3355 (class 2606 OID 25383) +-- Name: items fk_30a35cbe; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.items + ADD CONSTRAINT fk_30a35cbe FOREIGN KEY (dbtoon_id) REFERENCES public.toons(id); + + +-- +-- TOC entry 3346 (class 2606 OID 25388) +-- Name: craft_data fk_3b963ff3; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.craft_data + ADD CONSTRAINT fk_3b963ff3 FOREIGN KEY (dbgameaccount_id) REFERENCES public.game_accounts(id); + + +-- +-- TOC entry 3351 (class 2606 OID 25393) +-- Name: guild_news fk_514446fe; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.guild_news + ADD CONSTRAINT fk_514446fe FOREIGN KEY (dbguild_id) REFERENCES public.guilds(id); + + +-- +-- TOC entry 3354 (class 2606 OID 25398) +-- Name: hireling_data fk_5fc5407c; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.hireling_data + ADD CONSTRAINT fk_5fc5407c FOREIGN KEY (dbtoon_id) REFERENCES public.toons(id); + + +-- +-- TOC entry 3361 (class 2606 OID 25403) +-- Name: reports fk_6a424906; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.reports + ADD CONSTRAINT fk_6a424906 FOREIGN KEY (dbtoon_id) REFERENCES public.toons(id); + + +-- +-- TOC entry 3347 (class 2606 OID 25408) +-- Name: game_accounts fk_6a4a92e7; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.game_accounts + ADD CONSTRAINT fk_6a4a92e7 FOREIGN KEY (lastplayedhero_id) REFERENCES public.toons(id); + + +-- +-- TOC entry 3357 (class 2606 OID 25413) +-- Name: mail fk_731b838f; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.mail + ADD CONSTRAINT fk_731b838f FOREIGN KEY (dbtoon_id) REFERENCES public.toons(id); + + +-- +-- TOC entry 3358 (class 2606 OID 25418) +-- Name: quests fk_87f0b0fa; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.quests + ADD CONSTRAINT fk_87f0b0fa FOREIGN KEY (dbtoon_id) REFERENCES public.toons(id); + + +-- +-- TOC entry 3349 (class 2606 OID 25423) +-- Name: guild_members fk_8da26c16; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.guild_members + ADD CONSTRAINT fk_8da26c16 FOREIGN KEY (dbgameaccount_id) REFERENCES public.game_accounts(id); + + +-- +-- TOC entry 3340 (class 2606 OID 25428) +-- Name: account_relations fk_90774aff; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.account_relations + ADD CONSTRAINT fk_90774aff FOREIGN KEY (listtarget_id) REFERENCES public.accounts(id); + + +-- +-- TOC entry 3344 (class 2606 OID 25433) +-- Name: collection_editions fk_99f1c08; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.collection_editions + ADD CONSTRAINT fk_99f1c08 FOREIGN KEY (dbaccount_id) REFERENCES public.accounts(id); + + +-- +-- TOC entry 3353 (class 2606 OID 25438) +-- Name: guilds fk_9f1b0c33; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.guilds + ADD CONSTRAINT fk_9f1b0c33 FOREIGN KEY (creator_id) REFERENCES public.game_accounts(id); + + +-- +-- TOC entry 3352 (class 2606 OID 25443) +-- Name: guild_news fk_ab47ab3b; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.guild_news + ADD CONSTRAINT fk_ab47ab3b FOREIGN KEY (dbgameaccount_id) REFERENCES public.game_accounts(id); + + +-- +-- TOC entry 3356 (class 2606 OID 25448) +-- Name: items fk_b1c0d926; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.items + ADD CONSTRAINT fk_b1c0d926 FOREIGN KEY (dbgameaccount_id) REFERENCES public.game_accounts(id); + + +-- +-- TOC entry 3345 (class 2606 OID 25453) +-- Name: collection_editions fk_bd7cdba7; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.collection_editions + ADD CONSTRAINT fk_bd7cdba7 FOREIGN KEY (claimedtoon_id) REFERENCES public.toons(id); + + +-- +-- TOC entry 3341 (class 2606 OID 25458) +-- Name: account_relations fk_c49249a1; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.account_relations + ADD CONSTRAINT fk_c49249a1 FOREIGN KEY (listowner_id) REFERENCES public.accounts(id); + + +-- +-- TOC entry 3350 (class 2606 OID 25463) +-- Name: guild_members fk_d675c298; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.guild_members + ADD CONSTRAINT fk_d675c298 FOREIGN KEY (dbguild_id) REFERENCES public.guilds(id); + + +-- +-- TOC entry 3363 (class 2606 OID 25468) +-- Name: toons fk_e9da060c; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.toons + ADD CONSTRAINT fk_e9da060c FOREIGN KEY (dbgameaccount_id) REFERENCES public.game_accounts(id); + + +-- +-- TOC entry 3342 (class 2606 OID 25473) +-- Name: accounts fk_eac13c47; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.accounts + ADD CONSTRAINT fk_eac13c47 FOREIGN KEY (inviteeaccount_id) REFERENCES public.accounts(id); + + +-- +-- TOC entry 3348 (class 2606 OID 25478) +-- Name: game_accounts fk_edbee460; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.game_accounts + ADD CONSTRAINT fk_edbee460 FOREIGN KEY (dbaccount_id) REFERENCES public.accounts(id); + + +-- +-- TOC entry 3547 (class 0 OID 0) +-- Dependencies: 5 +-- Name: SCHEMA public; Type: ACL; Schema: -; Owner: postgres +-- + +GRANT ALL ON SCHEMA public TO PUBLIC; + + +-- Completed on 2022-08-18 16:47:30 UTC + +-- +-- PostgreSQL database dump complete +-- + diff --git a/db/pgadmin/pgpass b/db_old/pgadmin/pgpass similarity index 100% rename from db/pgadmin/pgpass rename to db_old/pgadmin/pgpass diff --git a/db/servers.json b/db_old/servers.json similarity index 100% rename from db/servers.json rename to db_old/servers.json diff --git a/docs/game-world-settings.md b/docs/game-world-settings.md index 8863def..0c60118 100644 --- a/docs/game-world-settings.md +++ b/docs/game-world-settings.md @@ -1,81 +1,76 @@ # Game World Settings -The parameters of the world can be easily altered using the configuration file located within `config.ini`. +The parameters of the world can be easily altered using the configuration file located within `config.maps.json`, which is built on server initialization. + +For older configs, it will be migrated from `config.ini` automatically. ## Configuration -The parameters specified in the `config.ini` file will be saved to the server folder, overwriting the default settings. For example, all values below use their default settings. +The parameters specified in the `config.mods.json` file will be created on the server folder, migrating from config.ini, to overwrite the default settings. For example, all values below use their default settings. -```ini -[Game-Server] -; rates -RateExp = 1 -RateMoney = 1 -RateDrop = 1 -RateChangeDrop = 1 -RateMonsterHP = 1 -RateMonsterDMG = 1 -; items -ChanceHighQualityUnidentified = 30 -ChanceNormalUnidentified = 5 -; bosses -BossHealthMultiplier = 6 -BossDamageMultiplier = 3 -; nephalem -NephalemRiftProgressMultiplier = 1 -NephalemRiftAutoFinish = false -NephalemRiftAutoFinishThreshold = 2 -NephalemRiftOrbsChance = 0 -; health -HealthPotionRestorePercentage = 60 -HealthPotionCooldown = 30 -ResurrectionCharges = 3 -; waypoints -UnlockAllWaypoints = false -; player attribute modifier -StrengthMultiplier = 1 -StrengthParagonMultiplier = 1 -DexterityMultiplier = 1 -DexterityParagonMultiplier = 1 -IntelligenceMultiplier = 1 -IntelligenceParagonMultiplier = 1 -VitalityMultiplier = 1 -VitalityParagonMultiplier = 1 -; quests -AutoSaveQuests = false -; minimap -ForceMinimapVisibility = false -``` +The default configuration can be found at [config.mods.json](https://github.com/blizzless/blizzless-diiis/blob/community/configs/config.mods.json) ## Description -| Key | Description | -| ---------------- | ------------------------- | -| `RateExp` | Experience multiplier | -| `RateMoney` | Currency multiplier | -| `RateDrop` | Drop quantity multiplier | -| `RateChangeDrop` | Drop quality multiplier | -| `RateMonsterHP` | Monsters HP multiplier | -| `RateMonsterDMG` | Monster damage multiplier | -| `ChanceHighQualityUnidentified` | Percentage that a unique, legendary, set or special item created is unidentified | -| `ChanceNormalUnidentified` | Percentage that normal item created is unidentified | -| `ResurrectionCharges` | Amount of times user can resurrect at corpse | -| `BossHealthMultiplier` | Boss Health Multiplier | -| `BossDamageMultiplier` | Boss Damage Multiplier | -| `HealthPotionRestorePercentage` | How much (from 1-100) a health potion will heal. | -| `HealthPotionCooldown` | How much (in seconds) to use a health potion again. | -| `UnlockAllWaypoints` | Unlocks all waypoints in campaign | -| `StrengthMultiplier` | Player's strength multiplier | -| `StrengthParagonMultiplier` | Player's strength multiplier **for paragons** | -| `DexterityMultiplier` | Player's dexterity multiplier | -| `DexterityParagonMultiplier` | Player's dexterity multiplier **for paragons** | -| `IntelligenceMultiplier` | Player's intelligence multiplier | -| `IntelligenceParagonMultiplier` | Player's intelligence multiplier **for paragons** | -| `VitalityMultiplier` | Player's vitality multiplier | -| `VitalityParagonMultiplier` | Player's vitality multiplier **for paragons** | -| `AutoSaveQuests` *in tests* | Force Save Quests/Step, even if Act's quest setup marked as Saveable = FALSE. Doesn't apply to OpenWorld games. | -| `NephalemRiftProgressMultiplier` | Nephalem Rift Progress Modifier | -| `NephalemRiftAutoFinish` | Nephalem Auto-Finish when there's still `NephalemRiftAutoFinishThreshold` monsters or less are alive on the rift | -| `NephalemRiftAutoFinishThreshold` | Nephalem Rift Progress Modifier | -| `NephalemRiftOrbsChance` | Nephalem Rifts chance of spawning a orb. | -| `ForceMinimapVisibility` | Forces the minimap visibility | +```json +{ + "Rate": { + "Experience": 1.0, // Experience Rate + "Money": 1.0, // money rate + "Drop": 1.0, // drop rate + "ChangeDrop": 1.0 // change drop rate + }, + "Health": { + "PotionRestorePercentage": 60.0, // how many in percent will a potion restore + "PotionCooldown": 30.0, // how many seconds for a full potion recharge + "ResurrectionCharges": 3 // how many times can you revive at corpse + }, + "Monster": { + "HealthMultiplier": 1.0, // monster health multiplier + "DamageMultiplier": 1.0 // monster damage multiplier + }, + "Boss": { + "HealthMultiplier": 6.0, // boss health multiplier + "DamageMultiplier": 3.0 // boss damage multiplier + }, + "Quest": { + "AutoSave": false, // auto save at every quest + "UnlockAllWaypoints": false // unlocks all waypoints in-game + }, + "Player": { + "Multipliers": { // multipliers for the player (e.g. a paragon might need twice these values for fairer gameplay) + "Strength": { + "Normal": 1.0, + "Paragon": 1.0 + }, + "Dexterity": { + "Normal": 1.0, + "Paragon": 1.0 + }, + "Intelligence": { + "Normal": 1.0, + "Paragon": 1.0 + }, + "Vitality": { + "Normal": 1.0, + "Paragon": 1.0 + } + } + }, + "Items": { + "UnidentifiedDropChances": { // chances in % of a dropped item to be unidentified + "HighQuality": 30.0, + "NormalQuality": 5.0 + } + }, + "Minimap": { + "ForceVisibility": false // forces in-game minimap to be always visible + }, + "NephalemRift": { // improves overall nephalem rift experience + "ProgressMultiplier": 1.0, + "AutoFinish": false, + "AutoFinishThreshold": 2, + "OrbsChance": 2.0 // chances of spawning an orb + } +} +``` diff --git a/pictures/b3.PNG b/pictures/b3.PNG new file mode 100644 index 0000000..c090d1e Binary files /dev/null and b/pictures/b3.PNG differ diff --git a/pictures/d30.PNG b/pictures/d30.PNG new file mode 100644 index 0000000..edd7250 Binary files /dev/null and b/pictures/d30.PNG differ diff --git a/pictures/d32.PNG b/pictures/d32.PNG new file mode 100644 index 0000000..851dedf Binary files /dev/null and b/pictures/d32.PNG differ diff --git a/pictures/d33.PNG b/pictures/d33.PNG new file mode 100644 index 0000000..0a43cda Binary files /dev/null and b/pictures/d33.PNG differ diff --git a/pictures/d34.PNG b/pictures/d34.PNG new file mode 100644 index 0000000..4472367 Binary files /dev/null and b/pictures/d34.PNG differ diff --git a/pictures/d35.PNG b/pictures/d35.PNG new file mode 100644 index 0000000..84d6180 Binary files /dev/null and b/pictures/d35.PNG differ diff --git a/pictures/d36.PNG b/pictures/d36.PNG new file mode 100644 index 0000000..46cacb2 Binary files /dev/null and b/pictures/d36.PNG differ diff --git a/pictures/d37.PNG b/pictures/d37.PNG new file mode 100644 index 0000000..c75fbac Binary files /dev/null and b/pictures/d37.PNG differ diff --git a/pictures/d38.PNG b/pictures/d38.PNG new file mode 100644 index 0000000..a8b5d9c Binary files /dev/null and b/pictures/d38.PNG differ diff --git a/src/DiIiS-NA/BGS-Server/AccountsSystem/Account.cs b/src/DiIiS-NA/BGS-Server/AccountsSystem/Account.cs index 9c299ed..2792374 100644 --- a/src/DiIiS-NA/BGS-Server/AccountsSystem/Account.cs +++ b/src/DiIiS-NA/BGS-Server/AccountsSystem/Account.cs @@ -37,7 +37,7 @@ namespace DiIiS_NA.LoginServer.AccountsSystem { ByteStringPresenceField val = null; if (GameAccount.CurrentToon != null) - val = new ByteStringPresenceField(FieldKeyHelper.Program.D3, FieldKeyHelper.OriginatingClass.Account, 1, 0, GameAccount.CurrentToon.D3EntityID); + val = new ByteStringPresenceField(FieldKeyHelper.Program.D3, FieldKeyHelper.OriginatingClass.Account, 1, 0, GameAccount.CurrentToon.D3EntityId); else { var Fake = D3.OnlineService.EntityId.CreateBuilder().SetIdHigh(0).SetIdLow(0); diff --git a/src/DiIiS-NA/BGS-Server/AccountsSystem/GameAccount.cs b/src/DiIiS-NA/BGS-Server/AccountsSystem/GameAccount.cs index a1269c7..e3f680c 100644 --- a/src/DiIiS-NA/BGS-Server/AccountsSystem/GameAccount.cs +++ b/src/DiIiS-NA/BGS-Server/AccountsSystem/GameAccount.cs @@ -90,8 +90,8 @@ public class GameAccount : PersistentRPCObject public EntityId LastPlayedHeroId => CurrentToon == null - ? Toons.Count > 0 ? Toons.First().D3EntityID : AccountHasNoToons - : CurrentToon.D3EntityID; + ? Toons.Count > 0 ? Toons.First().D3EntityId : AccountHasNoToons + : CurrentToon.D3EntityId; public ByteStringPresenceField PartyIdField => new(FieldKeyHelper.Program.D3, FieldKeyHelper.OriginatingClass.Party, 1, 0) @@ -271,7 +271,7 @@ public class GameAccount : PersistentRPCObject _currentToonId = value.PersistentID; lock (DBGameAccount) { - SetField(x=>x.LastPlayedHero = value.DBToon); + SetField(x=>x.LastPlayedHero = value.DbToon); } ChangedFields.SetPresenceFieldValue(LastPlayedHeroIdField); @@ -924,9 +924,9 @@ public class GameAccount : PersistentRPCObject foreach (var hero in Toons) profile.AddHeroes(HeroMiniProfile.CreateBuilder() .SetHeroName(hero.Name) - .SetHeroGbidClass((int)hero.ClassID) + .SetHeroGbidClass((int)hero.ClassId) .SetHeroFlags((uint)hero.Flags) - .SetHeroId((uint)hero.D3EntityID.IdLow) + .SetHeroId((uint)hero.D3EntityId.IdLow) .SetHeroLevel(hero.Level) .SetHeroVisualEquipment(hero.HeroVisualEquipmentField.Value) ); @@ -1423,7 +1423,7 @@ public class GameAccount : PersistentRPCObject } else if (queryKey.Group == 3 && queryKey.Field == 1) // Hero's class (GbidClass) { - field.SetValue(bgs.protocol.Variant.CreateBuilder().SetIntValue(CurrentToon.ClassID).Build()); + field.SetValue(bgs.protocol.Variant.CreateBuilder().SetIntValue(CurrentToon.ClassId).Build()); } else if (queryKey.Group == 3 && queryKey.Field == 2) // Hero's current level { diff --git a/src/DiIiS-NA/BGS-Server/Base/ConnectHandler.cs b/src/DiIiS-NA/BGS-Server/Base/ConnectHandler.cs index 1546a37..970f918 100644 --- a/src/DiIiS-NA/BGS-Server/Base/ConnectHandler.cs +++ b/src/DiIiS-NA/BGS-Server/Base/ConnectHandler.cs @@ -250,6 +250,8 @@ namespace DiIiS_NA.LoginServer.Base } internal class WebSocketServerProtocolHandshakeHandler : ChannelHandlerAdapter { + + static readonly Logger _logger = LogManager.CreateLogger(); private readonly string websocketPath; private readonly string subprotocols; @@ -290,12 +292,16 @@ namespace DiIiS_NA.LoginServer.Base { if (!object.Equals(req.Method, HttpMethod.Get)) { - SendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.Http11, HttpResponseStatus.Forbidden)); + SendHttpResponse(ctx, req, + new DefaultFullHttpResponse(HttpVersion.Http11, HttpResponseStatus.Forbidden)); return; } + //v1.rpc.battle.net // - WebSocketServerHandshakerFactory webSocketServerHandshakerFactory = new WebSocketServerHandshakerFactory(GetWebSocketLocation(ctx.Channel.Pipeline, req, websocketPath), subprotocols, allowExtensions, maxFramePayloadSize, allowMaskMismatch); + WebSocketServerHandshakerFactory webSocketServerHandshakerFactory = + new WebSocketServerHandshakerFactory(GetWebSocketLocation(ctx.Channel.Pipeline, req, websocketPath), + subprotocols, allowExtensions, maxFramePayloadSize, allowMaskMismatch); WebSocketServerHandshaker handshaker = webSocketServerHandshakerFactory.NewHandshaker(req); if (handshaker == null) { @@ -303,7 +309,7 @@ namespace DiIiS_NA.LoginServer.Base return; } - handshaker.HandshakeAsync(ctx.Channel, req).ContinueWith(delegate (Task t) + handshaker.HandshakeAsync(ctx.Channel, req).ContinueWith(delegate(Task t) { if (t.Status != TaskStatus.RanToCompletion) { @@ -311,12 +317,17 @@ namespace DiIiS_NA.LoginServer.Base } else { - ctx.FireUserEventTriggered(new HandshakeHandler.HandshakeComplete(req.Uri, req.Headers, handshaker.SelectedSubprotocol)); + ctx.FireUserEventTriggered(new HandshakeHandler.HandshakeComplete(req.Uri, req.Headers, + handshaker.SelectedSubprotocol)); } }, TaskContinuationOptions.ExecuteSynchronously); HandshakeHandler.SetHandshaker(ctx.Channel, handshaker); ctx.Channel.Pipeline.Replace(this, "WS403Responder", HandshakeHandler.ForbiddenHttpRequestResponder()); } + catch (Exception ex) + { + _logger.ErrorException(ex, "Handshake failure"); + } finally { req.Release(); @@ -344,19 +355,12 @@ namespace DiIiS_NA.LoginServer.Base private static string GetWebSocketLocation(IChannelPipeline cp, IHttpRequest req, string path) { - string str = "ws"; - if (cp.Get() != null) - { - str = "wss"; - } + string protocol = cp.Get() != null ? "wss" : "ws"; - string str2 = null; - if (req.Headers.TryGet(HttpHeaderNames.Host, out ICharSequence value)) - { - str2 = value.ToString(); - } + // Ignore the Host header and default to a placeholder or IP address + string host = "192.168.1.100"; // Replace with your desired default host, e.g., the server's IP or DNS. - return str + "://" + str2 + path; + return $"{protocol}://{host}{path}"; } } } diff --git a/src/DiIiS-NA/BGS-Server/Battle/BattleBackend.cs b/src/DiIiS-NA/BGS-Server/Battle/BattleBackend.cs index 528cc20..36099f3 100644 --- a/src/DiIiS-NA/BGS-Server/Battle/BattleBackend.cs +++ b/src/DiIiS-NA/BGS-Server/Battle/BattleBackend.cs @@ -73,9 +73,11 @@ namespace DiIiS_NA.LoginServer.Battle switch (message[0]) { case "rngsr": + Logger.Info("test"); if (GameServers.ContainsKey(ipPort)) GameServers.Remove(ipPort); string rgsIp = args[0]; int rgsPort = int.Parse(args[1].Trim()); + Logger.Info("Range IP {0}:{1}", rgsIp, rgsPort); GameServers.Add(ipPort, new ServerDescriptor { GameIp = rgsIp, GamePort = rgsPort }); Logger.Info("Game server was registered for Blizzless {0}:{1}.", rgsIp, rgsPort); break; diff --git a/src/DiIiS-NA/BGS-Server/Battle/BattleClient.cs b/src/DiIiS-NA/BGS-Server/Battle/BattleClient.cs index dfc604d..2610b82 100644 --- a/src/DiIiS-NA/BGS-Server/Battle/BattleClient.cs +++ b/src/DiIiS-NA/BGS-Server/Battle/BattleClient.cs @@ -16,6 +16,8 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using System.Net.Http; +using System.Net.Http.Json; using System.Net.Security; using System.Threading.Tasks; using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Text; @@ -501,10 +503,41 @@ namespace DiIiS_NA.LoginServer.Battle } public void SendMotd() { - if (string.IsNullOrWhiteSpace(LoginServerConfig.Instance.Motd) || !LoginServerConfig.Instance.MotdEnabled) - return; - Logger.Debug($"Motd sent to {Account.BattleTag}."); - SendServerWhisper(LoginServerConfig.Instance.Motd); + if (LoginServerConfig.Instance.MotdEnabled) + { + if (LoginServerConfig.Instance.MotdEnabledRemote) + { + if (string.IsNullOrWhiteSpace(LoginServerConfig.Instance.MotdRemoteUrl)) + { + Logger.Warn("No Motd remote URL defined, falling back to normal motd."); + } + else + { + var url = LoginServerConfig.Instance.MotdRemoteUrl.Trim(); + HttpClient client = new(); + var post = client.PostAsJsonAsync(url, new + { + GameAccountId = InGameClient.Player?.Toon?.GameAccountId ?? 0, + ToonName = InGameClient.Player?.Toon?.Name ?? string.Empty, + WorldGlobalId = InGameClient.Player?.World?.GlobalID ?? 0 + }).Result; + if (post.IsSuccessStatusCode) + { + var text = post.Content.ReadAsStringAsync().Result; + SendServerWhisper(text); + Logger.Info("Remote Motd sent successfully."); + return; + } + + Logger.Warn("Could not POST to $[red]$" + url + "$[/]$. Please ensure the URL is correct. Falling back to normal MotD if available."); + } + } + if (!string.IsNullOrWhiteSpace(LoginServerConfig.Instance.Motd)) + { + Logger.Debug($"Motd sent to {Account.BattleTag}."); + SendServerWhisper(LoginServerConfig.Instance.Motd); + } + } } public override void ChannelInactive(IChannelHandlerContext context) diff --git a/src/DiIiS-NA/BGS-Server/Crypthography/ARC4.cs b/src/DiIiS-NA/BGS-Server/Crypthography/ARC4.cs index 5aca7ad..8742604 100644 --- a/src/DiIiS-NA/BGS-Server/Crypthography/ARC4.cs +++ b/src/DiIiS-NA/BGS-Server/Crypthography/ARC4.cs @@ -32,10 +32,8 @@ { index2 = (byte)(key[index1] + _state[counter] + index2); // swap byte - byte tmp = _state[counter]; - _state[counter] = _state[index2]; - _state[index2] = tmp; - index1 = (byte)((index1 + 1) % key.Length); + (_state[counter], _state[index2]) = (_state[index2], _state[counter]); + index1 = (byte)((index1 + 1) % key.Length); } } @@ -46,11 +44,9 @@ x = (byte)(x + 1); y = (byte)(_state[x] + y); // swap byte - byte tmp = _state[x]; - _state[x] = _state[y]; - _state[y] = tmp; + (_state[x], _state[y]) = (_state[y], _state[x]); - byte xorIndex = (byte)(_state[x] + _state[y]); + byte xorIndex = (byte)(_state[x] + _state[y]); outputBuffer[outputOffset + counter] = (byte)(inputBuffer[inputOffset + counter] ^ _state[xorIndex]); } return inputCount; diff --git a/src/DiIiS-NA/BGS-Server/GamesSystem/GameDescriptor.cs b/src/DiIiS-NA/BGS-Server/GamesSystem/GameDescriptor.cs index 1608d6d..67e9395 100644 --- a/src/DiIiS-NA/BGS-Server/GamesSystem/GameDescriptor.cs +++ b/src/DiIiS-NA/BGS-Server/GamesSystem/GameDescriptor.cs @@ -46,9 +46,9 @@ namespace DiIiS_NA.LoginServer.GamesSystem { this.GameCreateParams = D3.OnlineService.GameCreateParams.ParseFrom(attribute.Value.BlobValue); if (this.GameCreateParams.CreationFlags == 256 || this.GameCreateParams.CreationFlags == 262400) this.Public = true; - lock (owner.Account.GameAccount.CurrentToon.DBToon) + lock (owner.Account.GameAccount.CurrentToon.DbToon) { - var toonByClient = owner.Account.GameAccount.CurrentToon.DBToon; + var toonByClient = owner.Account.GameAccount.CurrentToon.DbToon; toonByClient.CurrentAct = this.GameCreateParams.CampaignOrAdventureMode.Act; toonByClient.CurrentQuestId = (this.GameCreateParams.CampaignOrAdventureMode.SnoQuest == 0 ? 87700 : this.GameCreateParams.CampaignOrAdventureMode.SnoQuest); toonByClient.CurrentQuestStepId = (this.GameCreateParams.CampaignOrAdventureMode.QuestStepId == 0 ? -1 : this.GameCreateParams.CampaignOrAdventureMode.QuestStepId); @@ -75,7 +75,7 @@ namespace DiIiS_NA.LoginServer.GamesSystem public void StartGame(List clients, ulong objectId) { Logger.MethodTrace($"objectId: {objectId}"); - var owner = this.Owner.Account.GameAccount.CurrentToon.DBToon; + var owner = this.Owner.Account.GameAccount.CurrentToon.DbToon; if (Program.BattleBackend.GameServers.Count == 0) return; diff --git a/src/DiIiS-NA/BGS-Server/LoginServerConfig.cs b/src/DiIiS-NA/BGS-Server/LoginServerConfig.cs index 40649bf..47dc93c 100644 --- a/src/DiIiS-NA/BGS-Server/LoginServerConfig.cs +++ b/src/DiIiS-NA/BGS-Server/LoginServerConfig.cs @@ -47,6 +47,12 @@ namespace DiIiS_NA.LoginServer get => GetBoolean(nameof(MotdEnabled), true); set => Set(nameof(MotdEnabled), value); } + + public bool MotdEnabledWhenWorldLoads + { + get => GetBoolean(nameof(MotdEnabledWhenWorldLoads), false); + set => Set(nameof(MotdEnabledWhenWorldLoads), value); + } /// /// Motd text @@ -54,10 +60,22 @@ namespace DiIiS_NA.LoginServer public string Motd { get => GetString(nameof(Motd), - $"Welcome to Blizzless Server Build {Program.Build} - Stage: {Program.Stage} [{Program.TypeBuild}]!"); + $"Welcome to Blizzless Server Build {Program.BUILD} - Stage: {Program.STAGE} [{Program.TypeBuild}]!"); set => Set(nameof(Motd), value); } + public bool MotdEnabledRemote + { + get => GetBoolean(nameof(MotdEnabledRemote), false); + set => Set(nameof(MotdEnabledRemote), value); + } + + public string MotdRemoteUrl + { + get => GetString(nameof(MotdRemoteUrl), ""); + set => Set(nameof(MotdRemoteUrl), value); + } + public static readonly LoginServerConfig Instance = new(); private LoginServerConfig() : base("Battle-Server") diff --git a/src/DiIiS-NA/BGS-Server/ServicesSystem/Services/ChannelService.cs b/src/DiIiS-NA/BGS-Server/ServicesSystem/Services/ChannelService.cs index c947ba7..d727234 100644 --- a/src/DiIiS-NA/BGS-Server/ServicesSystem/Services/ChannelService.cs +++ b/src/DiIiS-NA/BGS-Server/ServicesSystem/Services/ChannelService.cs @@ -97,9 +97,9 @@ namespace DiIiS_NA.LoginServer.ServicesSystem.Services var paramsBuilder = D3.OnlineService.GameCreateParams.CreateBuilder(gameCreateParams); var Mode = D3.OnlineService.CampaignOrAdventureModeCreateParams.CreateBuilder(gameCreateParams.CampaignOrAdventureMode); - lock (((HandlerController) controller).Client.Account.GameAccount.CurrentToon.DBToon) + lock (((HandlerController) controller).Client.Account.GameAccount.CurrentToon.DbToon) { - DBToon toonByClient = (((HandlerController) controller).Client).Account.GameAccount.CurrentToon.DBToon; + DBToon toonByClient = (((HandlerController) controller).Client).Account.GameAccount.CurrentToon.DbToon; if(toonByClient.CurrentAct == 400) toonByClient.CurrentAct = gameCreateParams.CampaignOrAdventureMode.Act; if (!clear_quests) @@ -152,7 +152,7 @@ namespace DiIiS_NA.LoginServer.ServicesSystem.Services { var gameCreateParamsBuilder = D3.OnlineService.GameCreateParams.CreateBuilder(); var toon = (((HandlerController) controller).Client).Account.GameAccount.CurrentToon; - var dbToon = (((HandlerController) controller).Client).Account.GameAccount.CurrentToon.DBToon; + var dbToon = (((HandlerController) controller).Client).Account.GameAccount.CurrentToon.DbToon; gameCreateParamsBuilder.SetGameType(1); gameCreateParamsBuilder.SetCreationFlags(0); gameCreateParamsBuilder.SetCampaignOrAdventureMode(D3.OnlineService.CampaignOrAdventureModeCreateParams.CreateBuilder() @@ -160,7 +160,7 @@ namespace DiIiS_NA.LoginServer.ServicesSystem.Services .SetAct(dbToon.CurrentAct) .SetSnoQuest(dbToon.CurrentQuestId) .SetQuestStepId(dbToon.CurrentQuestStepId) - .SetResumeFromSaveHeroId(toon.D3EntityID) + .SetResumeFromSaveHeroId(toon.D3EntityId) .SetDeprecatedOpenToFriends(true) .SetDeprecatedOpenToFriendsMessage("TestGame") ); diff --git a/src/DiIiS-NA/BGS-Server/ServicesSystem/Services/GameUtilitiesService.cs b/src/DiIiS-NA/BGS-Server/ServicesSystem/Services/GameUtilitiesService.cs index 58426b6..57356b9 100644 --- a/src/DiIiS-NA/BGS-Server/ServicesSystem/Services/GameUtilitiesService.cs +++ b/src/DiIiS-NA/BGS-Server/ServicesSystem/Services/GameUtilitiesService.cs @@ -64,7 +64,7 @@ namespace DiIiS_NA.LoginServer.ServicesSystem.Services foreach (Toon t in Client.Account.GameAccount.Toons) { d.AddDigestList(t.Digest); - GAS.AddHeroListOrder(t.D3EntityID); + GAS.AddHeroListOrder(t.D3EntityId); } Init.SetGameAccountSettings(GAS); @@ -77,7 +77,7 @@ namespace DiIiS_NA.LoginServer.ServicesSystem.Services const int anniversaryEventStatus = 1; const int challengeRiftNumber = 1; const bool freeToPlay = true; - const bool storeStatus = false; // false + const bool storeStatus = true; // false (true - disabled, false - enabled) const string catalogDigest = "C42DC6117A7008EDA2006542D6C07EAD096DAD90"; const string catalogVersion = "633565800390338000"; const int regionId = 1; @@ -92,8 +92,8 @@ namespace DiIiS_NA.LoginServer.ServicesSystem.Services $" OnlineService.Store.Status={(storeStatus ? "1" : "0")}" + //Store Status, 0 - Enabled, 1 - Disabled $" OnlineService.Store.ProductCatalogDigest={catalogDigest}" + //China $" OnlineService.Store.ProductCatalogVersion={catalogVersion}" + //Chinese Catalog - //" OnlineService.Store.ProductCatalogDigest=79162283AFACCBA5DA989BD341F7B782860AC1F4" + //Euro - //" OnlineService.Store.ProductCatalogVersion=635984100169931000" + //Euro + //" OnlineService.Store.ProductCatalogDigest=79162283AFACCBA5DA989BD341F7B782860AC1F4" + //Euro + //" OnlineService.Store.ProductCatalogVersion=635984100169931000" + //Euro $" OnlineService.Region.Id={regionId}"); //Region Init.SetSeenTutorials(ByteString.CopyFrom(Client.Account.GameAccount.DBGameAccount.SeenTutorials)); @@ -661,7 +661,7 @@ namespace DiIiS_NA.LoginServer.ServicesSystem.Services if (hero != null) { var Snapshot = D3.Leaderboard.HeroSnapshot.CreateBuilder() - .SetHeroId(hero.D3EntityID) + .SetHeroId(hero.D3EntityId) .AddCosmeticItems(D3.Leaderboard.HeroCosmeticItem.CreateBuilder().SetCosmeticVisualInventorySlot(1) .SetGbid(hero.Cosmetic1)) .AddCosmeticItems(D3.Leaderboard.HeroCosmeticItem.CreateBuilder().SetCosmeticVisualInventorySlot(2) @@ -671,21 +671,21 @@ namespace DiIiS_NA.LoginServer.ServicesSystem.Services .AddCosmeticItems(D3.Leaderboard.HeroCosmeticItem.CreateBuilder().SetCosmeticVisualInventorySlot(4) .SetGbid(hero.Cosmetic4)) .SetActiveSkills(SkillsWithRunes.CreateBuilder() - .AddRunes(SkillWithRune.CreateBuilder().SetSkill(hero.DBActiveSkills.Skill0) - .SetRuneType(hero.DBActiveSkills.Rune0)) - .AddRunes(SkillWithRune.CreateBuilder().SetSkill(hero.DBActiveSkills.Skill1) - .SetRuneType(hero.DBActiveSkills.Rune1)) - .AddRunes(SkillWithRune.CreateBuilder().SetSkill(hero.DBActiveSkills.Skill2) - .SetRuneType(hero.DBActiveSkills.Rune2)) - .AddRunes(SkillWithRune.CreateBuilder().SetSkill(hero.DBActiveSkills.Skill3) - .SetRuneType(hero.DBActiveSkills.Rune3)) - .AddRunes(SkillWithRune.CreateBuilder().SetSkill(hero.DBActiveSkills.Skill4) - .SetRuneType(hero.DBActiveSkills.Rune4)) - .AddRunes(SkillWithRune.CreateBuilder().SetSkill(hero.DBActiveSkills.Skill5) - .SetRuneType(hero.DBActiveSkills.Rune5))) - .SetActiveTraits(PassiveSkills.CreateBuilder().AddSnoTraits(hero.DBActiveSkills.Passive0) - .AddSnoTraits(hero.DBActiveSkills.Passive1).AddSnoTraits(hero.DBActiveSkills.Passive2) - .AddSnoTraits(hero.DBActiveSkills.Passive3)); + .AddRunes(SkillWithRune.CreateBuilder().SetSkill(hero.DbActiveSkills.Skill0) + .SetRuneType(hero.DbActiveSkills.Rune0)) + .AddRunes(SkillWithRune.CreateBuilder().SetSkill(hero.DbActiveSkills.Skill1) + .SetRuneType(hero.DbActiveSkills.Rune1)) + .AddRunes(SkillWithRune.CreateBuilder().SetSkill(hero.DbActiveSkills.Skill2) + .SetRuneType(hero.DbActiveSkills.Rune2)) + .AddRunes(SkillWithRune.CreateBuilder().SetSkill(hero.DbActiveSkills.Skill3) + .SetRuneType(hero.DbActiveSkills.Rune3)) + .AddRunes(SkillWithRune.CreateBuilder().SetSkill(hero.DbActiveSkills.Skill4) + .SetRuneType(hero.DbActiveSkills.Rune4)) + .AddRunes(SkillWithRune.CreateBuilder().SetSkill(hero.DbActiveSkills.Skill5) + .SetRuneType(hero.DbActiveSkills.Rune5))) + .SetActiveTraits(PassiveSkills.CreateBuilder().AddSnoTraits(hero.DbActiveSkills.Passive0) + .AddSnoTraits(hero.DbActiveSkills.Passive1).AddSnoTraits(hero.DbActiveSkills.Passive2) + .AddSnoTraits(hero.DbActiveSkills.Passive3)); foreach (var item in hero.Profile.Equipment.ItemsList) { @@ -842,7 +842,7 @@ namespace DiIiS_NA.LoginServer.ServicesSystem.Services .SetHeroAltLevel((uint)gameAccount2.DBGameAccount.ParagonLevel) .SetHeroFlags((uint)Hero.Flags) .SetHeroLevel((uint)Hero.Level) - .SetHeroGbidClass((uint)Hero.ClassID) + .SetHeroGbidClass((uint)Hero.ClassId) .SetHeroName(Hero.Name) .SetHeroSnapshotAvailable(true) .SetHeroVisualEquipment(gameAccount2.Toons[0].Digest.VisualEquipment); @@ -1001,7 +1001,7 @@ namespace DiIiS_NA.LoginServer.ServicesSystem.Services .SetHeroAltLevel((uint)gameAccount.DBGameAccount.ParagonLevel) .SetHeroFlags((uint)hero.Flags) .SetHeroLevel((uint)hero.Level) - .SetHeroGbidClass((uint)hero.ClassID) + .SetHeroGbidClass((uint)hero.ClassId) .SetHeroName(hero.Name) .SetHeroSnapshotAvailable(true) .SetHeroVisualEquipment(gameAccount.Toons[0].Digest.VisualEquipment); @@ -1097,7 +1097,7 @@ namespace DiIiS_NA.LoginServer.ServicesSystem.Services var newToon = ToonManager.CreateNewToon(createParams.Name, createParams.GbidClass, createParams.IsFemale ? ToonFlags.Female : ToonFlags.Male, 1, createParams.IsHardcore, client.Account.GameAccount, createParams.IsSeason ? 1 : 0); - return CreateHeroResponse.CreateBuilder().SetHeroId(newToon.D3EntityID.IdLow).Build().ToByteString(); + return CreateHeroResponse.CreateBuilder().SetHeroId(newToon.D3EntityId.IdLow).Build().ToByteString(); } private ByteString OnHeroDeleteParams(BattleClient client, ByteString data) @@ -3118,7 +3118,7 @@ namespace DiIiS_NA.LoginServer.ServicesSystem.Services var Response = RebirthHeroResponse.CreateBuilder(); foreach (Toon t in client.Account.GameAccount.Toons) { - if (t.D3EntityID.IdLow == Request.HeroId) + if (t.D3EntityId.IdLow == Request.HeroId) { //t.SetSeason(1); diff --git a/src/DiIiS-NA/BGS-Server/Toons/Toon.cs b/src/DiIiS-NA/BGS-Server/Toons/Toon.cs index 6b3b93f..f06e21e 100644 --- a/src/DiIiS-NA/BGS-Server/Toons/Toon.cs +++ b/src/DiIiS-NA/BGS-Server/Toons/Toon.cs @@ -19,12 +19,12 @@ namespace DiIiS_NA.LoginServer.Toons public int Cosmetic1 { - get => DBToon.Cosmetic1; + get => DbToon.Cosmetic1; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.Cosmetic1 = value; DBSessions.SessionUpdate(dbToon); } @@ -33,12 +33,12 @@ namespace DiIiS_NA.LoginServer.Toons public int Cosmetic2 { - get => DBToon.Cosmetic2; + get => DbToon.Cosmetic2; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.Cosmetic2 = value; DBSessions.SessionUpdate(dbToon); } @@ -47,12 +47,12 @@ namespace DiIiS_NA.LoginServer.Toons public int Cosmetic3 { - get => DBToon.Cosmetic3; + get => DbToon.Cosmetic3; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.Cosmetic3 = value; DBSessions.SessionUpdate(dbToon); } @@ -61,12 +61,12 @@ namespace DiIiS_NA.LoginServer.Toons public int Cosmetic4 { - get => DBToon.Cosmetic4; + get => DbToon.Cosmetic4; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.Cosmetic4 = value; DBSessions.SessionUpdate(dbToon); } @@ -75,7 +75,7 @@ namespace DiIiS_NA.LoginServer.Toons #endregion - public DBToon DBToon + public DBToon DbToon { get; /* @@ -93,11 +93,11 @@ namespace DiIiS_NA.LoginServer.Toons set; } - private DBToon CachedDBToon { get; set; } + private DBToon CachedDbToon { get; set; } public bool IsHardcore { get; set; } - public DBActiveSkills DBActiveSkills + public DBActiveSkills DbActiveSkills { get { return DBSessions.SessionQuerySingle(s => s.DBToon.Id == PersistentID); } set { } @@ -108,7 +108,7 @@ namespace DiIiS_NA.LoginServer.Toons get { var val = new IntPresenceField(FieldKeyHelper.Program.D3, FieldKeyHelper.OriginatingClass.Hero, 1, 0, - ClassID); + ClassId); return val; } } @@ -152,13 +152,13 @@ namespace DiIiS_NA.LoginServer.Toons FieldKeyHelper.OriginatingClass.Hero, 5, 0, _heroName); private D3.Hero.VisualEquipment _visualEquipment = null; - public bool _visualEquipmentChanged = true; + public bool VisualEquipmentChanged = true; public ByteStringPresenceField HeroVisualEquipmentField { get { - if (_visualEquipmentChanged) + if (VisualEquipmentChanged) { var visualItems = new[] { @@ -171,7 +171,7 @@ namespace DiIiS_NA.LoginServer.Toons D3.Hero.VisualItem.CreateBuilder().SetEffectLevel(0).Build(), // Shoulders D3.Hero.VisualItem.CreateBuilder().SetEffectLevel(0).Build(), // Legs }; - var CosmeticItems = new[] + var cosmeticItems = new[] { D3.Hero.VisualCosmeticItem.CreateBuilder().SetGbid(Cosmetic1).Build(), // Wings D3.Hero.VisualCosmeticItem.CreateBuilder().SetGbid(Cosmetic2).Build(), // Flag @@ -197,8 +197,8 @@ namespace DiIiS_NA.LoginServer.Toons } _visualEquipment = D3.Hero.VisualEquipment.CreateBuilder().AddRangeVisualItem(visualItems) - .AddRangeCosmeticItem(CosmeticItems).Build(); - _visualEquipmentChanged = false; + .AddRangeCosmeticItem(cosmeticItems).Build(); + VisualEquipmentChanged = false; } return new ByteStringPresenceField(FieldKeyHelper.Program.D3, @@ -212,19 +212,19 @@ namespace DiIiS_NA.LoginServer.Toons /// /// D3 EntityID encoded id. /// - public D3.OnlineService.EntityId D3EntityID { get; private set; } + public D3.OnlineService.EntityId D3EntityId { get; private set; } /// /// True if toon has been recently deleted; /// public bool Deleted { - get => DBToon.Deleted; + get => DbToon.Deleted; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.Deleted = value; DBSessions.SessionUpdate(dbToon); } @@ -235,12 +235,12 @@ namespace DiIiS_NA.LoginServer.Toons public int SeasonCreated { - get => DBToon.CreatedSeason; + get => DbToon.CreatedSeason; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.CreatedSeason = value; DBSessions.SessionUpdate(dbToon); } @@ -249,12 +249,12 @@ namespace DiIiS_NA.LoginServer.Toons public bool StoneOfPortal { - get => DBToon.StoneOfPortal; + get => DbToon.StoneOfPortal; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.StoneOfPortal = value; DBSessions.SessionUpdate(dbToon); } @@ -263,12 +263,12 @@ namespace DiIiS_NA.LoginServer.Toons public bool Dead { - get => DBToon.Dead; + get => DbToon.Dead; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.Dead = value; DBSessions.SessionUpdate(dbToon); } @@ -280,12 +280,12 @@ namespace DiIiS_NA.LoginServer.Toons /// public bool Archieved { - get => DBToon.Archieved; + get => DbToon.Archieved; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.Archieved = value; DBSessions.SessionUpdate(dbToon); } @@ -319,9 +319,9 @@ namespace DiIiS_NA.LoginServer.Toons set { _heroName = value; - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.Name = value; DBSessions.SessionUpdate(dbToon); } @@ -350,9 +350,9 @@ namespace DiIiS_NA.LoginServer.Toons set { GameAccountId = value.PersistentID; - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.DBGameAccount = value.DBGameAccount; DBSessions.SessionUpdate(dbToon); } @@ -414,9 +414,9 @@ namespace DiIiS_NA.LoginServer.Toons set { _flags = value; - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.Flags = value; DBSessions.SessionUpdate(dbToon); } @@ -440,7 +440,7 @@ namespace DiIiS_NA.LoginServer.Toons { if (_levelChanged || !LoginServerConfig.Instance.Enabled) { - _cachedLevel = DBToon.Level; + _cachedLevel = DbToon.Level; _levelChanged = false; } @@ -448,10 +448,10 @@ namespace DiIiS_NA.LoginServer.Toons } private set { - lock (DBToon) + lock (DbToon) { _cachedLevel = value; - var dbToon = DBToon; + var dbToon = DbToon; dbToon.Level = value; DBSessions.SessionUpdate(dbToon); } @@ -459,7 +459,7 @@ namespace DiIiS_NA.LoginServer.Toons } private int _cachedParagonLevel = 0; - public bool _paragonLevelChanged = true; + public bool ParagonLevelChanged = true; /// /// Toon's Paragon level. @@ -468,9 +468,9 @@ namespace DiIiS_NA.LoginServer.Toons { get { - if (!_paragonLevelChanged && LoginServerConfig.Instance.Enabled) return _cachedParagonLevel; + if (!ParagonLevelChanged && LoginServerConfig.Instance.Enabled) return _cachedParagonLevel; _cachedParagonLevel = GameAccount.DBGameAccount.ParagonLevel; - _paragonLevelChanged = false; + ParagonLevelChanged = false; return _cachedParagonLevel; } @@ -494,16 +494,16 @@ namespace DiIiS_NA.LoginServer.Toons /// public long ExperienceNext { - get => (Level >= 70 ? ParagonExperienceNext : DBToon.Experience); + get => (Level >= 70 ? ParagonExperienceNext : DbToon.Experience); set { if (Level >= 70) ParagonExperienceNext = value; else { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.Experience = value; DBSessions.SessionUpdate(dbToon); } @@ -530,12 +530,12 @@ namespace DiIiS_NA.LoginServer.Toons public int CurrentAct { - get => DBToon.CurrentAct; + get => DbToon.CurrentAct; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.CurrentAct = value; DBSessions.SessionUpdate(dbToon); } @@ -544,12 +544,12 @@ namespace DiIiS_NA.LoginServer.Toons public int CurrentQuestId { - get => DBToon.CurrentQuestId; + get => DbToon.CurrentQuestId; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.CurrentQuestId = value; DBSessions.SessionUpdate(dbToon); } @@ -558,12 +558,12 @@ namespace DiIiS_NA.LoginServer.Toons public int PvERating { - get => DBToon.PvERating; + get => DbToon.PvERating; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.PvERating = value; DBSessions.SessionUpdate(dbToon); } @@ -572,12 +572,12 @@ namespace DiIiS_NA.LoginServer.Toons public int CurrentQuestStepId { - get => DBToon.CurrentQuestStepId; + get => DbToon.CurrentQuestStepId; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.CurrentQuestStepId = value; DBSessions.SessionUpdate(dbToon); } @@ -586,12 +586,12 @@ namespace DiIiS_NA.LoginServer.Toons public int CurrentDifficulty { - get => DBToon.CurrentDifficulty; + get => DbToon.CurrentDifficulty; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.CurrentDifficulty = value; DBSessions.SessionUpdate(dbToon); } @@ -606,11 +606,11 @@ namespace DiIiS_NA.LoginServer.Toons get => GameAccount.DBGameAccount.TotalKilled; set { - var dbGA = GameAccount.DBGameAccount; - lock (dbGA) + var dbGa = GameAccount.DBGameAccount; + lock (dbGa) { - dbGA.TotalKilled = value; - DBSessions.SessionUpdate(dbGA); + dbGa.TotalKilled = value; + DBSessions.SessionUpdate(dbGa); } } } @@ -623,11 +623,11 @@ namespace DiIiS_NA.LoginServer.Toons get => GameAccount.DBGameAccount.ElitesKilled; set { - var dbGA = GameAccount.DBGameAccount; - lock (dbGA) + var dbGa = GameAccount.DBGameAccount; + lock (dbGa) { - dbGA.ElitesKilled = value; - DBSessions.SessionUpdate(dbGA); + dbGa.ElitesKilled = value; + DBSessions.SessionUpdate(dbGa); } } } @@ -650,19 +650,19 @@ namespace DiIiS_NA.LoginServer.Toons } set { - var dbGA = GameAccount.DBGameAccount; - lock (dbGA) + var dbGa = GameAccount.DBGameAccount; + lock (dbGa) { if (IsHardcore) { - dbGA.TotalBountiesHardcore = value; + dbGa.TotalBountiesHardcore = value; } else { - dbGA.TotalBounties = value; + dbGa.TotalBounties = value; } - DBSessions.SessionUpdate(dbGA); + DBSessions.SessionUpdate(dbGa); } } } @@ -672,10 +672,10 @@ namespace DiIiS_NA.LoginServer.Toons /// public int SeasonalKills { - get => DBToon.Kills; + get => DbToon.Kills; set { - var dbToon = DBToon; + var dbToon = DbToon; lock (dbToon) { dbToon.Kills = value; @@ -714,12 +714,12 @@ namespace DiIiS_NA.LoginServer.Toons /// public int CollectedGoldSeasonal { - get => DBToon.GoldGained; + get => DbToon.GoldGained; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.GoldGained = value; DBSessions.SessionUpdate(dbToon); } @@ -731,12 +731,12 @@ namespace DiIiS_NA.LoginServer.Toons /// public int TimePlayed { - get => DBToon.TimePlayed; + get => DbToon.TimePlayed; set { - lock (DBToon) + lock (DbToon) { - var dbToon = DBToon; + var dbToon = DbToon; dbToon.TimePlayed = value; DBSessions.SessionUpdate(dbToon); } @@ -751,7 +751,7 @@ namespace DiIiS_NA.LoginServer.Toons /// /// Database handler for this toon /// - public GameDBSession DBSession { get; set; } + public GameDBSession DbSession { get; set; } /// /// Settings for toon. @@ -772,14 +772,14 @@ namespace DiIiS_NA.LoginServer.Toons { get { - var dbToon = DBToon; + var dbToon = DbToon; if (IsHardcore) dbToon.Flags |= ToonFlags.Hardcore; //var isSeason = Convert.ToUInt16(isSeassoned); var digest = D3.Hero.Digest.CreateBuilder().SetVersion(905) - .SetHeroId(D3EntityID) + .SetHeroId(D3EntityId) .SetHeroName(Name) - .SetGbidClass((int)ClassID) + .SetGbidClass((int)ClassId) .SetLevel(Level) //deprecated //.SetAltLevel(dbToon.ParagonLevel) .SetPlayerFlags((uint)dbToon.Flags) // + isSeason) @@ -936,7 +936,7 @@ namespace DiIiS_NA.LoginServer.Toons .SetIdHigh(0x3C000002517A293 + invItem.Id)) .SetHirelingClass(0) .SetItemSlot(272 + invItem.EquipmentSlot * 16) - .SetOwnerEntityId(D3EntityID) + .SetOwnerEntityId(D3EntityId) .SetSquareIndex(0) .SetUsedSocketCount(0); @@ -1014,7 +1014,7 @@ namespace DiIiS_NA.LoginServer.Toons } //*/ - var dbToon = DBToon; + var dbToon = DbToon; string[] stats = dbToon.Stats.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); var profile = D3.Profile.HeroProfile.CreateBuilder() .SetHardcore(IsHardcore) @@ -1022,7 +1022,7 @@ namespace DiIiS_NA.LoginServer.Toons //deprecated //.SetLife(0) .SetSnoKillLocation(71150) .SetKillerInfo(D3.Profile.KillerInfo.CreateBuilder().SetSnoKiller(6031).SetRarity(4)) - .SetHeroId(D3EntityID) + .SetHeroId(D3EntityId) //deprecated //.SetHighestDifficulty(0) .SetHighestLevel(dbToon.Level) //.SetMonstersKilled(111) @@ -1045,9 +1045,9 @@ namespace DiIiS_NA.LoginServer.Toons //.SetResistCold(110) //.SetResistPoison(111) .SetEquipment(itemList); - if (DBActiveSkills != null) + if (DbActiveSkills != null) { - var dbActiveSkills = DBActiveSkills; + var dbActiveSkills = DbActiveSkills; var skills = new[] { D3.Profile.SkillWithRune.CreateBuilder() @@ -1104,7 +1104,7 @@ namespace DiIiS_NA.LoginServer.Toons } } - public int ClassID => + public int ClassId => Class switch { ToonClass.Barbarian => 0x4FB91EE2, @@ -1118,7 +1118,7 @@ namespace DiIiS_NA.LoginServer.Toons }; // Used for Conversations - public int VoiceClassID => + public int VoiceClassId => Class switch { ToonClass.DemonHunter => 0, @@ -1139,21 +1139,21 @@ namespace DiIiS_NA.LoginServer.Toons private readonly Dictionary _visualToSlotMapping = new() { { 1, 0 }, { 2, 1 }, { 7, 2 }, { 5, 3 }, { 4, 4 }, { 3, 5 }, { 8, 6 }, { 9, 7 } }; - private static readonly Core.MPQ.FileFormats.GameBalance HeroData = + public static readonly Core.MPQ.FileFormats.GameBalance HeroData = (Core.MPQ.FileFormats.GameBalance)MPQStorage.Data.Assets[SNOGroup.GameBalance][19740].Data; - public Toon(DBToon dbToon, GameDBSession DBSession = null) + public Toon(DBToon dbToon, GameDBSession dbSession = null) : base(dbToon.Id) { - D3EntityID = D3.OnlineService.EntityId.CreateBuilder().SetIdHigh((ulong)EntityIdHelper.HighIdType.ToonId) + D3EntityId = D3.OnlineService.EntityId.CreateBuilder().SetIdHigh((ulong)EntityIdHelper.HighIdType.ToonId) .SetIdLow(PersistentID).Build(); _heroName = dbToon.Name; _flags = dbToon.Flags; GameAccountId = dbToon.DBGameAccount.Id; _toonClass = dbToon.Class; - DBToon = dbToon; - this.DBSession = DBSession; + DbToon = dbToon; + this.DbSession = dbSession; IsHardcore = dbToon.isHardcore; IsSeasoned = dbToon.isSeasoned; HeroTable = HeroData.Heros.Find(item => item.Name == Class.ToString()); @@ -1190,7 +1190,7 @@ namespace DiIiS_NA.LoginServer.Toons { var questHistory = new DBQuestHistory { - DBToon = DBToon, + DBToon = DbToon, QuestId = quest, QuestStep = -1, isCompleted = true @@ -1209,8 +1209,8 @@ namespace DiIiS_NA.LoginServer.Toons public void StateChanged() { _levelChanged = true; - _paragonLevelChanged = true; - _visualEquipmentChanged = true; + ParagonLevelChanged = true; + VisualEquipmentChanged = true; } #region Notifications @@ -1242,7 +1242,7 @@ namespace DiIiS_NA.LoginServer.Toons #endregion - public static ToonClass GetClassByID(int classId) => + public static ToonClass GetClassById(int classId) => classId switch { 0x4FB91EE2 => ToonClass.Barbarian, @@ -1257,7 +1257,7 @@ namespace DiIiS_NA.LoginServer.Toons public override string ToString() { - return $"{{ Toon: {Name} [lowId: {D3EntityID.IdLow}] }}"; + return $"{{ Toon: {Name} [lowId: {D3EntityId.IdLow}] }}"; } } diff --git a/src/DiIiS-NA/BGS-Server/Toons/ToonManager.cs b/src/DiIiS-NA/BGS-Server/Toons/ToonManager.cs index 8154323..b3f59f9 100644 --- a/src/DiIiS-NA/BGS-Server/Toons/ToonManager.cs +++ b/src/DiIiS-NA/BGS-Server/Toons/ToonManager.cs @@ -240,7 +240,7 @@ namespace DiIiS_NA.LoginServer.Toons var newDBToon = new DBToon { - Class = @Toon.GetClassByID(classId), + Class = @Toon.GetClassById(classId), Name = name, /*HashCode = GetUnusedHashCodeForToonName(name),*/ Flags = toonFlags, @@ -309,19 +309,19 @@ namespace DiIiS_NA.LoginServer.Toons public static void CreateStartEquipment(Toon toon, bool isHardcore) { DBInventory pants = NewbiePants; - pants.DBToon = toon.DBToon; + pants.DBToon = toon.DbToon; pants.DBGameAccount = toon.GameAccount.DBGameAccount; pants.isHardcore = isHardcore; DBSessions.SessionSave(pants); DBInventory armor = NewbieArmor; - armor.DBToon = toon.DBToon; + armor.DBToon = toon.DbToon; armor.DBGameAccount = toon.GameAccount.DBGameAccount; armor.isHardcore = isHardcore; DBSessions.SessionSave(armor); DBInventory weapon; - switch (toon.DBToon.Class) + switch (toon.DbToon.Class) { case ToonClass.Barbarian: weapon = NewbieAxe; @@ -348,14 +348,14 @@ namespace DiIiS_NA.LoginServer.Toons weapon = NewbieKnife; break; } - weapon.DBToon = toon.DBToon; + weapon.DBToon = toon.DbToon; weapon.DBGameAccount = toon.GameAccount.DBGameAccount; weapon.isHardcore = isHardcore; DBSessions.SessionSave(weapon); - if (toon.DBToon.Class == ToonClass.Crusader) //add shield + if (toon.DbToon.Class == ToonClass.Crusader) //add shield { weapon = NewbieShield; - weapon.DBToon = toon.DBToon; + weapon.DBToon = toon.DbToon; weapon.DBGameAccount = toon.GameAccount.DBGameAccount; weapon.isHardcore = isHardcore; DBSessions.SessionSave(weapon); @@ -367,7 +367,7 @@ namespace DiIiS_NA.LoginServer.Toons DBSessions.SessionSave(new DBHireling { Class = type, - DBToon = toon.DBToon, + DBToon = toon.DbToon, Skill1SNOId = -1, Skill2SNOId = -1, Skill3SNOId = -1, diff --git a/src/DiIiS-NA/Blizzless.csproj b/src/DiIiS-NA/Blizzless.csproj index fc13cc4..92625c6 100644 --- a/src/DiIiS-NA/Blizzless.csproj +++ b/src/DiIiS-NA/Blizzless.csproj @@ -11,6 +11,7 @@ DiIiS_NA.Program full Debug;Release;github + win-x64;linux-x64 @@ -118,6 +119,9 @@ Always + + PreserveNewest + diff --git a/src/DiIiS-NA/Core/Extensions/DataConversionExtensions.cs b/src/DiIiS-NA/Core/Extensions/DataConversionExtensions.cs new file mode 100644 index 0000000..1bf1357 --- /dev/null +++ b/src/DiIiS-NA/Core/Extensions/DataConversionExtensions.cs @@ -0,0 +1,11 @@ +using System; + +namespace DiIiS_NA.Core.Extensions; + +public static class MathConversionsOperations +{ + public static int Floor(this float value) => (int) Math.Floor(value); + public static int Ceiling(this float value) => (int) Math.Ceiling(value); + public static int Floor(this double value) => (int) Math.Floor(value); + public static int Ceil(this double value) => (int) Math.Floor(value); +} \ No newline at end of file diff --git a/src/DiIiS-NA/Core/Extensions/ListExtensions.cs b/src/DiIiS-NA/Core/Extensions/ListExtensions.cs index 2eed864..f8139e0 100644 --- a/src/DiIiS-NA/Core/Extensions/ListExtensions.cs +++ b/src/DiIiS-NA/Core/Extensions/ListExtensions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; namespace DiIiS_NA.Core.Extensions { @@ -6,22 +7,12 @@ namespace DiIiS_NA.Core.Extensions { public static bool ContainsAtLeastOne(this List list1, List list2) { - foreach (T m in list2) - { - if (list1.Contains(m)) - return true; - } - return false; + return list2.Any(list1.Contains); } public static bool ContainsAtLeastOne(this List list, T[] array) { - foreach (T m in array) - { - if (list.Contains(m)) - return true; - } - return false; + return array.Any(list.Contains); } } } diff --git a/src/DiIiS-NA/Core/Extensions/StringExtensions.cs b/src/DiIiS-NA/Core/Extensions/StringExtensions.cs index 0d9495f..89d9eda 100644 --- a/src/DiIiS-NA/Core/Extensions/StringExtensions.cs +++ b/src/DiIiS-NA/Core/Extensions/StringExtensions.cs @@ -44,15 +44,15 @@ namespace DiIiS_NA.Core.Extensions byteArray[indexBA++] = (byte)item; } - System.IO.MemoryStream ms = new System.IO.MemoryStream(byteArray); - System.IO.Compression.GZipStream sr = new System.IO.Compression.GZipStream(ms, + System.IO.MemoryStream ms = new(byteArray); + System.IO.Compression.GZipStream sr = new(ms, System.IO.Compression.CompressionMode.Decompress); byteArray = new byte[byteArray.Length]; int rByte = sr.Read(byteArray, 0, byteArray.Length); - System.Text.StringBuilder sB = new System.Text.StringBuilder(rByte); + System.Text.StringBuilder sB = new(rByte); for (int i = 0; i < rByte; i++) { sB.Append((char)byteArray[i]); diff --git a/src/DiIiS-NA/Core/Helpers/Math/FastRandom.cs b/src/DiIiS-NA/Core/Helpers/Math/FastRandom.cs index 1d99752..3be268f 100644 --- a/src/DiIiS-NA/Core/Helpers/Math/FastRandom.cs +++ b/src/DiIiS-NA/Core/Helpers/Math/FastRandom.cs @@ -219,4 +219,12 @@ namespace DiIiS_NA.Core.Helpers.Math /// public bool Chance(float successPercentage) => Next(100) < successPercentage; } + + public static class NumberExtensions + { + public static float ToFloat(this double value, int decimals = 4) => (float)System.Math.Round(value, decimals); + public static float ToFloat(this float value, int decimals = 4) => (float)System.Math.Round(value, decimals); + public static double ToDouble(this float value, int decimals = 4) => (double)System.Math.Round(value, decimals); + public static double ToDouble(this double value, int decimals = 4) => (double)System.Math.Round(value, decimals); + } } diff --git a/src/DiIiS-NA/Core/Helpers/Math/RandomHelper.cs b/src/DiIiS-NA/Core/Helpers/Math/RandomHelper.cs index 657c971..2d07fde 100644 --- a/src/DiIiS-NA/Core/Helpers/Math/RandomHelper.cs +++ b/src/DiIiS-NA/Core/Helpers/Math/RandomHelper.cs @@ -23,6 +23,21 @@ public static class RandomHelper return Random.Next(minValue, maxValue); } + public static float NextFloat() + { + return (float)Random.NextDouble(); + } + + public static float NextFloat(float min, float max) + { + return min + (float)Random.NextDouble() * (max - min); + } + + public static float NextFloat(float max) + { + return (float)Random.NextDouble() * max; + } + public static void NextBytes(byte[] buffer) { Random.NextBytes(buffer); diff --git a/src/DiIiS-NA/Core/Logging/AnsiTarget.cs b/src/DiIiS-NA/Core/Logging/AnsiTarget.cs index c0a37b6..5a99285 100644 --- a/src/DiIiS-NA/Core/Logging/AnsiTarget.cs +++ b/src/DiIiS-NA/Core/Logging/AnsiTarget.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -24,12 +26,12 @@ public class AnsiTarget : LogTarget _table = new Table().Expand().ShowFooters().ShowHeaders().Border(TableBorder.Rounded); if (IncludeTimeStamps) - _table.AddColumn("Time"); + _table.AddColumn("Time").Centered(); _table - .AddColumn("Level") - .AddColumn("Logger") - .AddColumn("Message") - .AddColumn("Error"); + .AddColumn("Level").RightAligned() + .AddColumn("Message").Centered() + .AddColumn("Logger").LeftAligned() + .AddColumn("Error").RightAligned(); AnsiConsole.Live(_table).StartAsync(async ctx => { @@ -56,14 +58,17 @@ public class AnsiTarget : LogTarget }); } - public static void StopIfRunning() + public static void StopIfRunning(bool clear = false) { CancellationTokenSource.Cancel(); while(!_shutdown) Thread.Sleep(100); Thread.Sleep(1000); - AnsiConsole.Clear(); - AnsiConsole.Cursor.SetPosition(0,0); + if (clear) + { + AnsiConsole.Clear(); + AnsiConsole.Cursor.SetPosition(0, 0); + } } /// @@ -98,6 +103,15 @@ public class AnsiTarget : LogTarget } + private static Dictionary _replacements = new () + { + ["["] = "[[", + ["]"] = "]]", + ["$[[/]]$"] = "[/]", + ["$[["] = "[", + ["]]$"] = "]" + }; + /// /// Performs a cleanup on the target. /// All [ becomes [[, and ] becomes ]] (for ignoring ANSI codes) @@ -109,124 +123,85 @@ public class AnsiTarget : LogTarget /// /// /// - string Cleanup(string x) => Beautify(x.Replace("[", "[[").Replace("]", "]]").Replace("$[[/]]$", "[/]").Replace("$[[", "[").Replace("]]$", "]")); - + public static string Cleanup(string input) + { + if (string.IsNullOrEmpty(input)) return ""; + return Beautify(_replacements.Aggregate(input, (current, replacement) => current.Replace(replacement.Key, replacement.Value))); + } public override void LogMessage(Logger.Level level, string logger, string message) { - if (CancellationTokenSource.IsCancellationRequested) - return; + if (CancellationTokenSource.IsCancellationRequested) return; + try { - if (IncludeTimeStamps) - _table.AddRow( - new Markup(DateTime.Now.ToString(TimeStampFormat), GetStyleByLevel(level)), - new Markup(level.ToString(), GetStyleByLevel(level)).RightJustified(), - new Markup(logger, GetStyleByLevel(level)).LeftJustified(), - new Markup(Cleanup(message), GetStyleByLevel(level)).LeftJustified(), - new Markup("", new Style(foreground: Color.Green3_1)).Centered()); - else - _table.AddRow( - new Markup(level.ToString()).RightJustified(), - new Markup(logger, GetStyleByLevel(level)).LeftJustified(), - new Markup(Cleanup(message), GetStyleByLevel(level)).LeftJustified(), - new Markup("", new Style(foreground: Color.Green3_1)).Centered()); + AddRow(level, logger, message, ""); } catch (Exception ex) { - var regex = new Regex(@"\$\[.*?\]\$"); - var matches = regex.Matches(message); - foreach (Match match in matches) - { - message = message.Replace(match.Value, ""); - } - - if (IncludeTimeStamps) - { - _table.AddRow( - new Markup(DateTime.Now.ToString(TimeStampFormat), GetStyleByLevel(level)), - new Markup(level.ToString(), GetStyleByLevel(level)).RightJustified(), - new Markup(logger, GetStyleByLevel(level)).LeftJustified(), - new Markup(Cleanup(message), GetStyleByLevel(level)).LeftJustified(), - new Markup(ex.Message, new Style(foreground: Color.Red3_1)).Centered()); - } - else - { - _table.AddRow( - new Markup(level.ToString()).RightJustified(), - new Markup(logger, GetStyleByLevel(level)).LeftJustified(), - new Markup(Cleanup(message), GetStyleByLevel(level)).LeftJustified(), - new Markup(ex.Message, new Style(foreground: Color.Red3_1)).Centered()); - } + AddRow(level, logger, Cleanup(StripMarkup(message)), ex.Message, true); } } public override void LogException(Logger.Level level, string logger, string message, Exception exception) { - if (CancellationTokenSource.IsCancellationRequested) - return; + if (CancellationTokenSource.IsCancellationRequested) return; + try { - if (IncludeTimeStamps) - _table.AddRow( - new Markup(DateTime.Now.ToString(TimeStampFormat), GetStyleByLevel(level)), - new Markup(level.ToString(), GetStyleByLevel(level)).RightJustified(), - new Markup(logger, GetStyleByLevel(level)).LeftJustified(), - new Markup(Cleanup(message), GetStyleByLevel(level)).LeftJustified(), - new Markup( - $"[underline red3_1 on white]{exception.GetType().Name}[/]\n" + Cleanup(exception.Message), - new Style(foreground: Color.Red3_1)).Centered()); - else - _table.AddRow( - new Markup(level.ToString()).RightJustified(), - new Markup(logger, GetStyleByLevel(level)).LeftJustified(), - new Markup(message, GetStyleByLevel(level)).LeftJustified(), - new Markup( - $"[underline red3_1 on white]{exception.GetType().Name}[/]\n" + Cleanup(exception.Message), - new Style(foreground: Color.Red3_1)).Centered()); + AddRow(level, logger, message, $"[underline red3_1 on white]{exception.GetType().Name}[/]\n" + Cleanup(exception.Message), exFormat: true); } catch (Exception ex) { - var regex = new Regex(@"\$\[.*?\]\$"); - var matches = regex.Matches(message); - foreach (Match match in matches) - { - message = message.Replace(match.Value, ""); - } - - if (IncludeTimeStamps) - { - _table.AddRow( - new Markup(DateTime.Now.ToString(TimeStampFormat), GetStyleByLevel(level)), - new Markup(level.ToString(), GetStyleByLevel(level)).RightJustified(), - new Markup(logger, GetStyleByLevel(level)).LeftJustified(), - new Markup(Cleanup(message), GetStyleByLevel(level)).LeftJustified(), - new Markup(ex.Message, new Style(foreground: Color.Red3_1)).Centered()); - } - else - { - _table.AddRow( - new Markup(level.ToString()).RightJustified(), - new Markup(logger, GetStyleByLevel(level)).LeftJustified(), - new Markup(Cleanup(message), GetStyleByLevel(level)).LeftJustified(), - new Markup(ex.Message, new Style(foreground: Color.Red3_1)).Centered()); - } + AddRow(level, logger, Cleanup(StripMarkup(message)), ex.Message, true); } -} + } + + private void AddRow(Logger.Level level, string logger, string message, string exMessage, bool isError = false, + bool exFormat = false) + { + Style messageStyle = GetStyleByLevel(level); + Style exStyle = exFormat ? new Style(foreground: Color.Red3_1) : new Style(foreground: Color.Green3_1); + var colTimestamp = new Markup(DateTime.Now.ToString(TimeStampFormat), messageStyle).Centered(); + var colLevel = new Markup(level.ToString(), messageStyle).RightJustified(); + var colMessage = new Markup(Cleanup(message), messageStyle).Centered(); + var colLogger = new Markup(logger, new Style(messageStyle.Foreground, messageStyle.Background, messageStyle.Decoration + #if DEBUG + //, link = ... + #endif + )).LeftJustified(); + var colError = new Markup(isError ? exMessage : "", exStyle).RightJustified(); + if (IncludeTimeStamps) _table.AddRow(colTimestamp, colLevel, colMessage, colLogger, colError); + else _table.AddRow(colLevel, colMessage, colLogger, colError); + } + + private string StripMarkup(string message) + { + var regex = new Regex(@"\$\[.*?\]\$"); + var matches = regex.Matches(message); + foreach (Match match in matches) + { + message = message.Replace(match.Value, ""); + } + + return message; + } private static Style GetStyleByLevel(Logger.Level level) { return level switch { - Logger.Level.RenameAccountLog => new Style(Color.DarkSlateGray3),// - Logger.Level.ChatMessage => new Style(Color.DarkSlateGray2),// - Logger.Level.Debug => new Style(Color.Olive),// - Logger.Level.MethodTrace => new Style(Color.DarkOliveGreen1_1),// - Logger.Level.Trace => new Style(Color.BlueViolet),// - Logger.Level.Info => new Style(Color.White), - Logger.Level.Success => new Style(Color.Green3_1), - Logger.Level.Warn => new Style(Color.Yellow),// + Logger.Level.RenameAccountLog => new Style(Color.Gold1),// + Logger.Level.ChatMessage => new Style(Color.Plum2),// + Logger.Level.Debug => new Style(Color.Grey62),// + Logger.Level.MethodTrace => new Style(Color.Grey74, decoration: Decoration.Dim | Decoration.Italic),// + Logger.Level.Trace => new Style(Color.Grey82),// + Logger.Level.Info => new Style(Color.SteelBlue), + Logger.Level.Success => new Style(Color.DarkOliveGreen3_2), + Logger.Level.Warn => new Style(Color.DarkOrange),// Logger.Level.Error => new Style(Color.IndianRed1),// Logger.Level.Fatal => new Style(Color.Red3_1),// + Logger.Level.QuestInfo => new Style(Color.Plum2), + Logger.Level.QuestStep => new Style(Color.Plum3, decoration: Decoration.Dim), Logger.Level.PacketDump => new Style(Color.Maroon),// _ => new Style(Color.White) }; @@ -239,4 +214,7 @@ public static class AnsiTargetExtensions { return text.Replace("$[", "").Replace("]$", "").Replace("[", "[[").Replace("]", "]]"); } + + public static string StyleAnsi(this object obj, string style) => + $"$[{style}]$" + obj.ToString().EscapeMarkup() + "$[/]$"; } \ No newline at end of file diff --git a/src/DiIiS-NA/Core/Logging/ConsoleTarget.cs b/src/DiIiS-NA/Core/Logging/ConsoleTarget.cs index 390c89d..bd17b93 100644 --- a/src/DiIiS-NA/Core/Logging/ConsoleTarget.cs +++ b/src/DiIiS-NA/Core/Logging/ConsoleTarget.cs @@ -26,7 +26,7 @@ namespace DiIiS_NA.Core.Logging public override void LogMessage(Logger.Level level, string logger, string message) { var timeStamp = IncludeTimeStamps ? "[[" + DateTime.Now.ToString(TimeStampFormat) + "]] " : ""; - AnsiConsole.MarkupLine($"{timeStamp}{SetColor(level, true)}[[{level.ToString(),8}]][/] {SetColor(level)}[[{Cleanup(logger),20}]]: {Cleanup(message)}[/]"); + AnsiConsole.MarkupLine($"{timeStamp}{SetColor(level, true)}[[{level.ToString(),8}]][/] {SetColor(level)}[[{Cleanup(logger),20}]]: {AnsiTarget.Cleanup(message)}[/]"); } /// Log level. diff --git a/src/DiIiS-NA/Core/Logging/LogConfig.cs b/src/DiIiS-NA/Core/Logging/LogConfig.cs index 53e0586..651f409 100644 --- a/src/DiIiS-NA/Core/Logging/LogConfig.cs +++ b/src/DiIiS-NA/Core/Logging/LogConfig.cs @@ -73,6 +73,12 @@ get => GetString(nameof(TimeStampFormat), "dd/MM/yyyy HH:mm:ss"); set => Set(nameof(TimeStampFormat), value); } + + public bool MaximizeWhenEnabled + { + get => GetBoolean(nameof(MaximizeWhenEnabled), false); + set => Set(nameof(MaximizeWhenEnabled), value); + } public LogTargetConfig(string loggerName) : base(loggerName) { } } diff --git a/src/DiIiS-NA/Core/Logging/LogManager.cs b/src/DiIiS-NA/Core/Logging/LogManager.cs index dc3e7eb..b9a3c9f 100644 --- a/src/DiIiS-NA/Core/Logging/LogManager.cs +++ b/src/DiIiS-NA/Core/Logging/LogManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; namespace DiIiS_NA.Core.Logging { @@ -20,35 +21,31 @@ namespace DiIiS_NA.Core.Logging /// Available loggers. /// internal readonly static Dictionary Loggers = new(); - - /// - /// Creates and returns a logger named with declaring type. - /// - /// A instance. - public static Logger CreateLogger() - { - var frame = new StackFrame(1, false); // read stack frame. - var name = frame.GetMethod().DeclaringType.Name; // get declaring type's name. - - if (name == null) // see if we got a name. - throw new Exception("Error getting full name for declaring type."); - - return CreateLogger(name); // return the newly created logger. - } - + /// /// Creates and returns a logger with given name. /// /// /// A instance. - public static Logger CreateLogger(string name) + public static Logger CreateLogger(string? name = null, [CallerFilePath] string filePath = "") { + if (name == null) + { + var frame = new StackFrame(1, false); // read stack frame. + name = frame.GetMethod()?.DeclaringType?.Name ?? "Unknown"; // get declaring type's name. + } + if (!Loggers.ContainsKey(name)) // see if we already have instance for the given name. - Loggers.Add(name, new Logger(name)); // add it to dictionary of loggers. + Loggers.Add(name, new Logger(name, filePath)); // add it to dictionary of loggers. return Loggers[name]; // return the newly created logger. } + public static Logger CreateLogger([CallerFilePath] string filePath = "") + { + return CreateLogger(typeof(T).Name, filePath); + } + /// /// Attachs a new log target. /// diff --git a/src/DiIiS-NA/Core/Logging/Logger.cs b/src/DiIiS-NA/Core/Logging/Logger.cs index 8e3a012..2b6fa32 100644 --- a/src/DiIiS-NA/Core/Logging/Logger.cs +++ b/src/DiIiS-NA/Core/Logging/Logger.cs @@ -13,15 +13,17 @@ namespace DiIiS_NA.Core.Logging public class Logger { public string Name { get; protected set; } + public string FilePath { get; protected set; } /// /// A logger base type is used to create a logger instance. /// E.g. ConsoleTarget, FileTarget, etc. /// /// Logger name - public Logger(string name) + public Logger(string name, string filePath = null) { Name = name; + FilePath = filePath; } public enum Level @@ -66,6 +68,15 @@ namespace DiIiS_NA.Core.Logging /// Fatal messages (usually unrecoverable errors that leads to client or server crashes). /// Fatal, + + /// + /// The messages meant for quest general logging purposes. + /// + QuestInfo, + /// + /// The messages meant for quest logging purposes. + /// + QuestStep, /// /// Packet messages. /// @@ -105,14 +116,39 @@ namespace DiIiS_NA.Core.Logging /// The log message. public void MethodTrace(string message, [CallerMemberName] string methodName = "", [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) { + var m = $"$[darkolivegreen3_2]${methodName}()$[/]$"; #if DEBUG var fileName = Path.GetFileName(filePath); - Log(Level.MethodTrace, $"$[underline white]${fileName}:{lineNumber}$[/]$ $[darkolivegreen3_2]${methodName}()$[/]$: " + message, null); + Log(Level.MethodTrace, $"$[red]${fileName}:{lineNumber}$[/]$ in {m}: " + message, null); #else - Log(Level.MethodTrace, $"$[darkolivegreen3_2]${methodName}()$[/]$: " + message, null); + Log(Level.MethodTrace, $"{m}: " + message, null); #endif } + public void QuestStep(string message, [CallerMemberName] string methodName = "", + [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) + { + var m = $"$[darkolivegreen3_2]${methodName}()$[/]$"; +#if DEBUG + var fileName = Path.GetFileName(filePath); + Log(Level.MethodTrace, $"$[red]${fileName}:{lineNumber}$[/]$ in {m}: " + message, null); +#else + Log(Level.MethodTrace, $"{m}: " + message, null); +#endif + } + + public void QuestInfo(string message, [CallerMemberName] string methodName = "", + [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0) + { + var m = $"$[darkolivegreen3_2]${methodName}()$[/]$"; +#if DEBUG + var fileName = Path.GetFileName(filePath); + Log(Level.MethodTrace, $"$[red]${fileName}:{lineNumber}$[/]$ in {m}: " + message, null); +#else + Log(Level.MethodTrace, $"{m}: " + message, null); +#endif + } + /// The log message. public void Debug(string message) => Log(Level.Debug, message, null); @@ -153,7 +189,7 @@ namespace DiIiS_NA.Core.Logging /// The log message. /// Additional arguments. - public void Fatal(string message, params object[] args) => Log(Level.Fatal, message, args); + public void Fatal(string message, params object[] args) => Log(Level.Fatal, message, args); #endregion diff --git a/src/DiIiS-NA/Core/MPQ/Data.cs b/src/DiIiS-NA/Core/MPQ/Data.cs index 2b46703..e0defcd 100644 --- a/src/DiIiS-NA/Core/MPQ/Data.cs +++ b/src/DiIiS-NA/Core/MPQ/Data.cs @@ -79,7 +79,7 @@ namespace DiIiS_NA.Core.MPQ public void Init() { - Logger.Info("Loading Diablo III Assets.."); + Logger.Info("Loading Diablo III Assets..."); DictSNOAccolade = Dicts.LoadAccolade(); DictSNOAct = Dicts.LoadActs(); DictSNOActor = Dicts.LoadActors(); diff --git a/src/DiIiS-NA/Core/MPQ/MPQPatchChain.cs b/src/DiIiS-NA/Core/MPQ/MPQPatchChain.cs index 3a9040b..0f5c1a7 100644 --- a/src/DiIiS-NA/Core/MPQ/MPQPatchChain.cs +++ b/src/DiIiS-NA/Core/MPQ/MPQPatchChain.cs @@ -30,11 +30,11 @@ namespace DiIiS_NA.Core.MPQ var mpqFile = MPQStorage.GetMPQFile(file); if (mpqFile == null) { - Logger.Error("Cannot find base MPQ file: {0}.", file); + Logger.Fatal("Cannot find base MPQ file: $[white on red]${0}$[/]$.", file); return; } this.BaseMPQFiles.Add(mpqFile); - Logger.Trace("Added MPQ storage: {0}.", file); + Logger.Debug($"Added MPQ storage: $[white underline]${file}$[/]$."); } this.PatchPattern = patchPattern; @@ -45,7 +45,7 @@ namespace DiIiS_NA.Core.MPQ this.Loaded = true; else { - Logger.Error("Required patch-chain version {0} is not satified (found version: {1}).", this.RequiredVersion, topMostMPQVersion); + Logger.Error("Required patch-chain version {0} is not satisfied (found version: {1}).", this.RequiredVersion, topMostMPQVersion); } } diff --git a/src/DiIiS-NA/Core/Storage/AccountDataBase/SessionProvider.cs b/src/DiIiS-NA/Core/Storage/AccountDataBase/SessionProvider.cs index 2d102ea..638e00a 100644 --- a/src/DiIiS-NA/Core/Storage/AccountDataBase/SessionProvider.cs +++ b/src/DiIiS-NA/Core/Storage/AccountDataBase/SessionProvider.cs @@ -35,10 +35,13 @@ namespace DiIiS_NA.Core.Storage.AccountDataBase if (_config == null) { _config = new Configuration(); - _config = _config.Configure(Path.Combine(FileHelpers.AssemblyRoot, "database.Account.config")); +#if DEBUG + _config = _config.Configure(File.Exists(Path.Combine(FileHelpers.AssemblyRoot, "database.Account.Debug.config")) ? Path.Combine(FileHelpers.AssemblyRoot, "database.Account.Debug.config") : Path.Combine(FileHelpers.AssemblyRoot, "database.Account.config")); +#else + _config = _config.Configure(Path.Combine(FileHelpers.AssemblyRoot, "database.Account.config")); +#endif - - var replacedProperties = new Dictionary(); + var replacedProperties = new Dictionary(); foreach (var prop in _config.Properties) { var newvalue = prop.Value; diff --git a/src/DiIiS-NA/Core/Storage/WorldSceneBase/Provider.cs b/src/DiIiS-NA/Core/Storage/WorldSceneBase/Provider.cs index f575817..4accba4 100644 --- a/src/DiIiS-NA/Core/Storage/WorldSceneBase/Provider.cs +++ b/src/DiIiS-NA/Core/Storage/WorldSceneBase/Provider.cs @@ -35,8 +35,11 @@ namespace DiIiS_NA.Core.Storage.WorldSceneBase if (_config == null) { _config = new Configuration(); +#if DEBUG + _config = _config.Configure(File.Exists(Path.Combine(FileHelpers.AssemblyRoot, "database.Worlds.Debug.config")) ? Path.Combine(FileHelpers.AssemblyRoot, "database.Worlds.Debug.config") : Path.Combine(FileHelpers.AssemblyRoot, "database.Worlds.config")); +#else _config = _config.Configure(Path.Combine(FileHelpers.AssemblyRoot, "database.Worlds.config")); - +#endif var replacedProperties = new Dictionary(); foreach (var prop in _config.Properties) diff --git a/src/DiIiS-NA/D3-GameServer/ClientSystem/Base/Server.cs b/src/DiIiS-NA/D3-GameServer/ClientSystem/Base/Server.cs index f6c550a..75fe1f0 100644 --- a/src/DiIiS-NA/D3-GameServer/ClientSystem/Base/Server.cs +++ b/src/DiIiS-NA/D3-GameServer/ClientSystem/Base/Server.cs @@ -24,7 +24,7 @@ namespace DiIiS_NA.GameServer.ClientSystem.Base public event ConnectionEventHandler OnDisconnect; public event ConnectionDataEventHandler DataReceived; - protected static readonly Logger Logger = LogManager.CreateLogger("S"); + protected static readonly Logger Logger = LogManager.CreateLogger(); private static bool _disposed = false; public virtual void Run() { } @@ -43,7 +43,7 @@ namespace DiIiS_NA.GameServer.ClientSystem.Base Acceptor = new AsyncAcceptor(); if (!Acceptor.Start(bindIP, port)) { - Logger.Fatal("Listen failed to Start AsyncAcceptor on {0}", bindIP); + Logger.Fatal("Listen failed to Start AsyncAcceptor on {0}:{1}", bindIP, port); return false; } diff --git a/src/DiIiS-NA/D3-GameServer/ClientSystem/ClientManager.cs b/src/DiIiS-NA/D3-GameServer/ClientSystem/ClientManager.cs index b2dfefd..b224502 100644 --- a/src/DiIiS-NA/D3-GameServer/ClientSystem/ClientManager.cs +++ b/src/DiIiS-NA/D3-GameServer/ClientSystem/ClientManager.cs @@ -34,7 +34,7 @@ namespace DiIiS_NA.GameServer.ClientSystem public void Consume(GameClient client, GameMessage message) { - if (message is JoinBNetGameMessage) OnJoinGame(client, (JoinBNetGameMessage)message); + if (message is JoinBNetGameMessage gameMessage) OnJoinGame(client, gameMessage); } public void OnJoinGame(GameClient client, JoinBNetGameMessage message) diff --git a/src/DiIiS-NA/D3-GameServer/ClientSystem/GameServer.cs b/src/DiIiS-NA/D3-GameServer/ClientSystem/GameServer.cs index e518b84..d205cd4 100644 --- a/src/DiIiS-NA/D3-GameServer/ClientSystem/GameServer.cs +++ b/src/DiIiS-NA/D3-GameServer/ClientSystem/GameServer.cs @@ -33,10 +33,10 @@ namespace DiIiS_NA.GameServer.ClientSystem public override void Run() { - int Port = 2001; + int port = 2001; - if (!Listen(Program.GameServerIp, Port)) return; - Logger.Info("Game Server Started - {0}:{1}...", Program.GameServerIp, Port); + if (!Listen(Program.GameServerIp, port)) return; + Logger.Info("Game Server Started - {0}:{1}...", Program.GameServerIp, port); } } } diff --git a/src/DiIiS-NA/D3-GameServer/CommandManager/CommandManager.cs b/src/DiIiS-NA/D3-GameServer/CommandManager/CommandManager.cs index 56f648a..7b9c75c 100644 --- a/src/DiIiS-NA/D3-GameServer/CommandManager/CommandManager.cs +++ b/src/DiIiS-NA/D3-GameServer/CommandManager/CommandManager.cs @@ -119,7 +119,7 @@ namespace DiIiS_NA.GameServer.CommandManager output = $"Unknown command."; #endif - if (output == string.Empty) + if (string.IsNullOrEmpty(output)) return true; if (output.Contains("\n")) diff --git a/src/DiIiS-NA/D3-GameServer/CommandManager/Commands/GameCommand.cs b/src/DiIiS-NA/D3-GameServer/CommandManager/Commands/GameCommand.cs new file mode 100644 index 0000000..367897e --- /dev/null +++ b/src/DiIiS-NA/D3-GameServer/CommandManager/Commands/GameCommand.cs @@ -0,0 +1,18 @@ +using DiIiS_NA.Core.Logging; +using DiIiS_NA.D3_GameServer; +using DiIiS_NA.LoginServer.AccountsSystem; +using DiIiS_NA.LoginServer.Battle; + +namespace DiIiS_NA.GameServer.CommandManager; + +[CommandGroup("game", "Game Commands", Account.UserLevels.Admin, inGameOnly: false)] +public class GameCommand : CommandGroup +{ + private static readonly Logger Logger = LogManager.CreateLogger(); + [Command("reload-mods", "Reload all game mods file.", Account.UserLevels.Admin, inGameOnly: false)] + public void ReloadMods(string[] @params, BattleClient invokerClient) + { + GameModsConfig.ReloadSettings(); + invokerClient?.SendServerWhisper("Game mods updated successfully!"); + } +} \ No newline at end of file diff --git a/src/DiIiS-NA/D3-GameServer/CommandManager/Commands/SpeedCommand.cs b/src/DiIiS-NA/D3-GameServer/CommandManager/Commands/SpeedCommand.cs index 49ee918..644928b 100644 --- a/src/DiIiS-NA/D3-GameServer/CommandManager/Commands/SpeedCommand.cs +++ b/src/DiIiS-NA/D3-GameServer/CommandManager/Commands/SpeedCommand.cs @@ -37,6 +37,7 @@ public class SpeedCommand : CommandGroup if (speedValue <= baseSpeed) // Base Run Speed [Necrosummon] { playerSpeed[GameAttributes.Running_Rate] = baseSpeed; + playerSpeed.BroadcastChangedIfRevealed(); return $"Speed reset to Base Speed ({baseSpeed:0.000})."; } playerSpeed.FixedMap.Add(FixedAttribute.Speed, attr => attr[GameAttributes.Running_Rate] = speedValue); diff --git a/src/DiIiS-NA/D3-GameServer/CommandManager/Commands/UnlockArtCommand.cs b/src/DiIiS-NA/D3-GameServer/CommandManager/Commands/UnlockArtCommand.cs index a24cd2a..25f5967 100644 --- a/src/DiIiS-NA/D3-GameServer/CommandManager/Commands/UnlockArtCommand.cs +++ b/src/DiIiS-NA/D3-GameServer/CommandManager/Commands/UnlockArtCommand.cs @@ -1,4 +1,5 @@ -using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Hireling; +using System; +using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Hireling; using DiIiS_NA.LoginServer.AccountsSystem; using DiIiS_NA.LoginServer.Battle; diff --git a/src/DiIiS-NA/D3-GameServer/Core/InventoryGrid.cs b/src/DiIiS-NA/D3-GameServer/Core/InventoryGrid.cs index eff62eb..a77b944 100644 --- a/src/DiIiS-NA/D3-GameServer/Core/InventoryGrid.cs +++ b/src/DiIiS-NA/D3-GameServer/Core/InventoryGrid.cs @@ -281,7 +281,7 @@ namespace DiIiS_NA.GameServer.Core if (EquipmentSlot == 15) ownerPlayer.Inventory.SaveItemToDB(ownerPlayer.Toon.GameAccount.DBGameAccount, null, EquipmentSlotId.Stash, item); else - ownerPlayer.Inventory.SaveItemToDB(ownerPlayer.Toon.GameAccount.DBGameAccount, ownerPlayer.Toon.DBToon, EquipmentSlotId.Inventory, item); + ownerPlayer.Inventory.SaveItemToDB(ownerPlayer.Toon.GameAccount.DBGameAccount, ownerPlayer.Toon.DbToon, EquipmentSlotId.Inventory, item); } } diff --git a/src/DiIiS-NA/D3-GameServer/Core/Types/Math/Vector2F.cs b/src/DiIiS-NA/D3-GameServer/Core/Types/Math/Vector2F.cs index 1d39593..7dc6709 100644 --- a/src/DiIiS-NA/D3-GameServer/Core/Types/Math/Vector2F.cs +++ b/src/DiIiS-NA/D3-GameServer/Core/Types/Math/Vector2F.cs @@ -12,25 +12,13 @@ namespace DiIiS_NA.GameServer.Core.Types.Math private static Vector2F _unitX; private static Vector2F _unitY; - public static Vector2F Zero - { - get { return _zero; } - } + public static Vector2F Zero => _zero; - public static Vector2F One - { - get { return _one; } - } + public static Vector2F One => _one; - public static Vector2F UnitX - { - get { return _unitX; } - } + public static Vector2F UnitX => _unitX; - public static Vector2F UnitY - { - get { return _unitY; } - } + public static Vector2F UnitY => _unitY; public Vector2F(float x, float y) { diff --git a/src/DiIiS-NA/D3-GameServer/Core/Types/Math/Vector3D.cs b/src/DiIiS-NA/D3-GameServer/Core/Types/Math/Vector3D.cs index d271cf4..d39024c 100644 --- a/src/DiIiS-NA/D3-GameServer/Core/Types/Math/Vector3D.cs +++ b/src/DiIiS-NA/D3-GameServer/Core/Types/Math/Vector3D.cs @@ -7,6 +7,9 @@ using DiIiS_NA.Core.Storage; using System; using System.Numerics; using DiIiS_NA.Core.Helpers.Math; +using System.Collections.Generic; +using System.Linq; +using DiIiS_NA.GameServer.GSSystem.ActorSystem; namespace DiIiS_NA.GameServer.Core.Types.Math { @@ -113,6 +116,36 @@ namespace DiIiS_NA.GameServer.Core.Types.Math return ((x * x) + (y * y)) + (z * z); } + public static double Distance(Vector3D vector1, Vector3D vector2) + { + return ((vector1.X * vector2.X) + (vector1.Y * vector2.Y) + (vector1.Z * vector2.Z)); + } + + public static bool IsInDistanceSquared(Vector3D position, Vector3D relative, double distanceMax, double distanceMin = -1f) + { + var dist = Distance(position, relative); + return dist < distanceMax && dist > distanceMin; + } + + private static Random rand = new Random(); + + public Vector3D Around(float radius) + { + return Around(radius, radius, radius); + } + public Vector3D Around(float x, float y, float z) + { + float newX = X + ((float)rand.NextDouble() * 2 * x) - x; + float newY = Y + ((float)rand.NextDouble() * 2 * y) - y; + float newZ = Z + ((float)rand.NextDouble() * 2 * z) - z; + return new Vector3D(newX, newY, newZ); + } + + public Vector3D Around(Vector3D vector) + { + return Around(vector.X, vector.Y, vector.Z); + } + public static bool operator ==(Vector3D a, Vector3D b) => a?.Equals(b) ?? ReferenceEquals(null, b); public static bool operator !=(Vector3D a, Vector3D b) => !(a == b); @@ -167,5 +200,34 @@ namespace DiIiS_NA.GameServer.Core.Types.Math public override string ToString() => $"X:{X:F4}, Y:{Y:F4} Z:{Z:F4}"; public bool IsNear(Vector3D other, float distance) => DistanceSquared(ref other) < distance; - } + + public override int GetHashCode() => HashCode.Combine(X.ToDouble(decimals: 6), Y.ToDouble(decimals: 6), Z.ToDouble(decimals: 6)); + } + + public static class VectorExtensions + { + /// + /// Takes all actors from the given collection that are within the specified distance of the reference position. + /// + /// + /// + /// + /// + /// + public static TSearch[] WhereNearbyOf( + this IEnumerable actors, + TSearch[] referenceActors, + Func query, + double maxDistance = 50f, + double minDistance = 1f) + where TActor : Actor + where TSearch : Actor + { + return actors.OfType() + .Where(actor => query(actor)) + .Where((actor, dist) => + referenceActors.Any(refActor => refActor.GlobalID != actor.GlobalID && Vector3D.IsInDistanceSquared(refActor.Position, actor.Position, maxDistance, minDistance))) + .ToArray(); + } + } } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brain.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brain.cs index a0d46dd..2e546c2 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brain.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brain.cs @@ -47,7 +47,7 @@ namespace DiIiS_NA.GameServer.GSSystem.AISystem public virtual void Update(int tickCounter) { - if (State == BrainState.Dead || Body == null || Body.World == null || State == BrainState.Off) + if (State == BrainState.Dead || Body?.World == null || State == BrainState.Off) return; Think(tickCounter); // let the brain think. diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brains/MonsterBrain.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brains/MonsterBrain.cs index 6ea3910..e6a2f6d 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brains/MonsterBrain.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/AISystem/Brains/MonsterBrain.cs @@ -5,6 +5,7 @@ using DiIiS_NA.Core.Extensions; using DiIiS_NA.Core.Helpers.Math; using DiIiS_NA.Core.Logging; using DiIiS_NA.Core.MPQ; +using DiIiS_NA.D3_GameServer; using DiIiS_NA.D3_GameServer.Core.Types.SNO; using DiIiS_NA.GameServer.Core.Types.SNO; using DiIiS_NA.GameServer.Core.Types.TagMap; @@ -21,456 +22,532 @@ using DiIiS_NA.GameServer.MessageSystem; namespace DiIiS_NA.GameServer.GSSystem.AISystem.Brains { - public class MonsterBrain : Brain - { - private new readonly Logger Logger; - // list of power SNOs that are defined for the monster - public Dictionary PresetPowers { get; private set; } + public class MonsterBrain : Brain + { + private readonly Logger _logger; - private TickTimer _powerDelay; + // list of power SNOs that are defined for the monster + public Dictionary PresetPowers { get; private set; } - public struct Cooldown - { - public TickTimer CooldownTimer; - public float CooldownTime; - } + private TickTimer _powerDelay; - private bool _warnedNoPowers; - private Actor _target { get; set; } - private int _mpqPowerCount; - private bool Feared = false; + public struct Cooldown + { + public TickTimer CooldownTimer; + public float CooldownTime; + } - public Actor AttackedBy = null; - public TickTimer TimeoutAttacked = null; + private bool _warnedNoPowers; + private Actor Target { get; set; } + private readonly int _mpqPowerCount; + private bool _feared = false; - public Actor PriorityTarget = null; + public Actor AttackedBy = null; + public TickTimer TimeoutAttacked = null; - public MonsterBrain(Actor body) - : base(body) - { - Logger = LogManager.CreateLogger(GetType().Name); - - PresetPowers = new Dictionary(); + public Actor PriorityTarget = null; - // build list of powers defined in monster mpq data - if (body.ActorData.MonsterSNO <= 0) - { - Logger.Warn($"$[red]${GetType().Name}$[/]$ - Monster \"{body.SNO}\" has no monster SNO"); - return; - } - var monsterData = (DiIiS_NA.Core.MPQ.FileFormats.Monster)MPQStorage.Data.Assets[SNOGroup.Monster][body.ActorData.MonsterSNO].Data; - _mpqPowerCount = monsterData.SkillDeclarations.Count(e => e.SNOPower != -1); - for (int i = 0; i < monsterData.SkillDeclarations.Length; i++) - { - if (monsterData.SkillDeclarations[i].SNOPower == -1) continue; - if (PowerLoader.HasImplementationForPowerSNO(monsterData.SkillDeclarations[i].SNOPower)) - { - var cooldownTime = monsterData.MonsterSkillDeclarations[i].Timer / 10f; - PresetPowers.Add(monsterData.SkillDeclarations[i].SNOPower, new Cooldown { CooldownTimer = null, CooldownTime = cooldownTime }); - } - } + public MonsterBrain(Actor body) + : base(body) + { + _logger = LogManager.CreateLogger(GetType().Name); - if (monsterData.SkillDeclarations.All(s => s.SNOPower != 30592)) - PresetPowers.Add(30592, new Cooldown { CooldownTimer = null, CooldownTime = 0f }); //hack for dummy mobs without powers - } + PresetPowers = new Dictionary(); - public override void Think(int tickCounter) - { - switch (Body.SNO) - { - case ActorSno._uber_siegebreakerdemon: - case ActorSno._a4dun_garden_corruption_monster: - case ActorSno._a4dun_garden_hellportal_pillar: - case ActorSno._belialvoiceover: - return; - } + // build list of powers defined in monster mpq data + if (body.ActorData.MonsterSNO <= 0) + { + _logger.Warn($"$[red]${GetType().Name}$[/]$ - Monster \"{body.SNO}\" has no monster SNO"); + return; + } - if (Body.Hidden) - return; + var monsterData = + (DiIiS_NA.Core.MPQ.FileFormats.Monster)MPQStorage.Data.Assets[SNOGroup.Monster][ + body.ActorData.MonsterSNO].Data; + _mpqPowerCount = monsterData.SkillDeclarations.Count(e => e.SNOPower != -1); + for (int i = 0; i < monsterData.SkillDeclarations.Length; i++) + { + if (monsterData.SkillDeclarations[i].SNOPower == -1) continue; + if (!PowerLoader.HasImplementationForPowerSNO(monsterData.SkillDeclarations[i].SNOPower)) continue; + var cooldownTime = monsterData.MonsterSkillDeclarations[i].Timer / 10f; + PresetPowers.Add(monsterData.SkillDeclarations[i].SNOPower, + new Cooldown { CooldownTimer = null, CooldownTime = cooldownTime }); + } - if (CurrentAction != null && PriorityTarget != null && PriorityTarget.Attributes[GameAttributes.Is_Helper] == true) - { - PriorityTarget = null; - CurrentAction.Cancel(tickCounter); - CurrentAction = null; - return; - } + if (monsterData.SkillDeclarations.All(s => s.SNOPower != 30592)) + PresetPowers.Add(30592, + new Cooldown { CooldownTimer = null, CooldownTime = 0f }); //hack for dummy mobs without powers + } - if (tickCounter % 60 != 0) return; - - if (Body is NPC) return; + public override void Think(int tickCounter) + { + switch (Body.SNO) + { + case ActorSno._uber_siegebreakerdemon: + case ActorSno._a4dun_garden_corruption_monster: + case ActorSno._a4dun_garden_hellportal_pillar: + case ActorSno._belialvoiceover: + return; + } - if (!Body.Visible || Body.Dead) return; + if (Body.Hidden) + return; - if (Body.World.Game.Paused) return; - if (Body.Attributes[GameAttributes.Disabled]) return; + if (CurrentAction != null && PriorityTarget != null && + PriorityTarget.Attributes[GameAttributes.Is_Helper] == true) + { + PriorityTarget = null; + CurrentAction.Cancel(tickCounter); + CurrentAction = null; + return; + } - if (Body.Attributes[GameAttributes.Frozen] || - Body.Attributes[GameAttributes.Stunned] || - Body.Attributes[GameAttributes.Blind] || - Body.Attributes[GameAttributes.Webbed] || - Body.Disable || - Body.World.BuffManager.GetFirstBuff(Body) != null || - Body.World.BuffManager.GetFirstBuff(Body) != null) - { - if (CurrentAction != null) - { - CurrentAction.Cancel(tickCounter); - CurrentAction = null; - } - _powerDelay = null; + if (tickCounter % 60 != 0) return; - return; - } + if (Body is NPC) return; - if (Body.Attributes[GameAttributes.Feared]) - { - if (!Feared || CurrentAction == null) - { - if (CurrentAction != null) - { - CurrentAction.Cancel(tickCounter); - CurrentAction = null; - } - Feared = true; - CurrentAction = new MoveToPointWithPathfindAction( - Body, - PowerContext.RandomDirection(Body.Position, 3f, 8f) - ); - return; - } + if (!Body.Visible || Body.Dead) return; - return; - } + if (Body.World.Game.Paused) return; + if (Body.Attributes[GameAttributes.Disabled]) return; - Feared = false; + if (Body.Attributes[GameAttributes.Frozen] || + Body.Attributes[GameAttributes.Stunned] || + Body.Attributes[GameAttributes.Blind] || + Body.Attributes[GameAttributes.Webbed] || + Body.Disable || + Body.World.BuffManager.GetFirstBuff(Body) != null || + Body.World.BuffManager.GetFirstBuff(Body) != null) + { + if (CurrentAction != null) + { + CurrentAction.Cancel(tickCounter); + CurrentAction = null; + } - if (CurrentAction == null) - { - _powerDelay ??= new SecondsTickTimer(Body.World.Game, 1.0f); - if (AttackedBy != null || Body.GetObjectsInRange(50f).Count != 0) - { - if (_powerDelay.TimedOut) - { - _powerDelay = new SecondsTickTimer(Body.World.Game, 1.0f); + _powerDelay = null; - if (AttackedBy != null) - PriorityTarget = AttackedBy; + return; + } - if (PriorityTarget == null) - { - Actor[] targets; + if (Body.Attributes[GameAttributes.Feared]) + { + if (_feared && CurrentAction != null) return; + if (CurrentAction != null) + { + CurrentAction.Cancel(tickCounter); + CurrentAction = null; + } - if (Body.Attributes[GameAttributes.Team_Override] == 1) - targets = Body.GetObjectsInRange(60f) - .Where(p => !p.Dead) - .OrderBy((monster) => PowerMath.Distance2D(monster.Position, Body.Position)) - .ToArray(); - else - targets = Body.GetActorsInRange(50f) - .Where(p => ((p is Player) && !p.Dead && p.Attributes[GameAttributes.Loading] == false && p.Attributes[GameAttributes.Is_Helper] == false && p.World.BuffManager.GetFirstBuff(p) == null) - || ((p is Minion) && !p.Dead && p.Attributes[GameAttributes.Is_Helper] == false) - || (p is DesctructibleLootContainer && p.SNO.IsDoorOrBarricade()) - || ((p is Hireling) && !p.Dead) - ) - .OrderBy((actor) => PowerMath.Distance2D(actor.Position, Body.Position)) - .ToArray(); + _feared = true; + CurrentAction = new MoveToPointWithPathfindAction( + Body, + PowerContext.RandomDirection(Body.Position, 3f, 8f) + ); + return; + } - if (targets.Length == 0) return; - - _target = targets.First(); - } - else - _target = PriorityTarget; + _feared = false; - int powerToUse = PickPowerToUse(); - if (powerToUse > 0) - { - PowerScript power = PowerLoader.CreateImplementationForPowerSNO(powerToUse); - power.User = Body; - float attackRange = Body.ActorData.Cylinder.Ax2 + (power.EvalTag(PowerKeys.AttackRadius) > 0f ? (powerToUse == 30592 ? 10f : Math.Min((float)power.EvalTag(PowerKeys.AttackRadius), 35f)) : 35f); - float targetDistance = PowerMath.Distance2D(_target.Position, Body.Position); - if (targetDistance < attackRange + _target.ActorData.Cylinder.Ax2) - { - if (Body.WalkSpeed != 0) - Body.TranslateFacing(_target.Position, false); + if (CurrentAction != null) return; + _powerDelay ??= new SecondsTickTimer(Body.World.Game, 1.0f); + // Check if the character has been attacked or if there are any players within 50 units range + if (AttackedBy != null || Body.GetObjectsInRange(GameModsConfig.Instance.Monster.LookupRange).Count != 0) + { + // If the power delay hasn't timed out, return + if (!_powerDelay.TimedOut) return; - CurrentAction = new PowerAction(Body, powerToUse, _target); + // Reset the power delay + _powerDelay = new SecondsTickTimer(Body.World.Game, 1.0f); - if (power is SummoningSkill) - PresetPowers[powerToUse] = new Cooldown { CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f) }; + // If the character has been attacked, set the attacker as the priority target + if (AttackedBy != null) + PriorityTarget = AttackedBy; - if (power is MonsterAffixSkill monsterAffixSkill) - PresetPowers[powerToUse] = new Cooldown { CooldownTimer = null, CooldownTime = monsterAffixSkill.CooldownTime }; + // If there's no defined priority target, start a search + if (PriorityTarget == null) + { + Actor[] targets; - if (PresetPowers[powerToUse].CooldownTime > 0f) - PresetPowers[powerToUse] = new Cooldown { CooldownTimer = new SecondsTickTimer(Body.World.Game, PresetPowers[powerToUse].CooldownTime), CooldownTime = PresetPowers[powerToUse].CooldownTime }; + // If the character is part of a team, search for alive monsters within a range of 60 units and order them by distance + if (Body.Attributes[GameAttributes.Team_Override] == 1) + targets = Body.GetObjectsInRange(GameModsConfig.Instance.Monster.LookupRange +10f) + .Where(p => !p.Dead) + .OrderBy((monster) => PowerMath.Distance2D(monster.Position, Body.Position)) + .ToArray(); + else + // Otherwise, search for different types of actors including players, minions, destructible loot containers, or hirelings that are alive, not loading and not helpers, and order them by distance + targets = Body.GetActorsInRange(GameModsConfig.Instance.Monster.LookupRange) + .Where(p => ((p is Player) && !p.Dead && p.Attributes[GameAttributes.Loading] == false && + p.Attributes[GameAttributes.Is_Helper] == false && + p.World.BuffManager.GetFirstBuff(p) == null) + || ((p is Minion) && !p.Dead && p.Attributes[GameAttributes.Is_Helper] == false) + || (p is DesctructibleLootContainer && p.SNO.IsDoorOrBarricade()) + || ((p is Hireling) && !p.Dead) + ) + .OrderBy((actor) => PowerMath.Distance2D(actor.Position, Body.Position)) + .ToArray(); - if (powerToUse is 96925 or 223284) - PresetPowers[powerToUse] = new Cooldown { CooldownTimer = new SecondsTickTimer(Body.World.Game, 10f), CooldownTime = 10f }; - } - else if (Body.WalkSpeed != 0) - { - if (Body.SNO.IsWoodwraithOrWasp()) - { - Logger.Trace($"{GetType().Name} $[underline white]${nameof(MoveToPointAction)}$[/]$ to target $[white]${_target.ActorType}$[/]$ [{_target.Position}]"); - CurrentAction = new MoveToPointAction( - Body, _target.Position - ); - } - else - { - Logger.Trace($"{GetType().Name} {nameof(MoveToTargetWithPathfindAction)} to target [{_target.ActorType}] {_target.SNO.ToString()}"); - CurrentAction = new MoveToTargetWithPathfindAction( - Body, - _target, - attackRange + _target.ActorData.Cylinder.Ax2, - powerToUse - ); - } - } - else - { - powerToUse = Body.SNO switch - { - ActorSno._a1dun_leor_firewall2 => 223284, - _ => powerToUse - }; - CurrentAction = new PowerAction(Body, powerToUse, _target); + // If there are no targets, return + if (targets.Length == 0) return; - if (power is SummoningSkill) - PresetPowers[powerToUse] = new Cooldown { CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f) }; + // Set the first found target as the target + Target = targets.First(); + } + else + // If there is a priority target, set it as the target + Target = PriorityTarget; - if (power is MonsterAffixSkill) - PresetPowers[powerToUse] = new Cooldown { CooldownTimer = null, CooldownTime = (power as MonsterAffixSkill).CooldownTime }; + int powerToUse = PickPowerToUse(); + if (powerToUse <= 0) return; + PowerScript power = PowerLoader.CreateImplementationForPowerSNO(powerToUse); + power.User = Body; + float attackRange = Body.ActorData.Cylinder.Ax2 + (power.EvalTag(PowerKeys.AttackRadius) > 0f + ? (powerToUse == 30592 ? 10f : Math.Min((float)power.EvalTag(PowerKeys.AttackRadius), 35f)) + : 35f); + float targetDistance = PowerMath.Distance2D(Target.Position, Body.Position); + if (targetDistance < attackRange + Target.ActorData.Cylinder.Ax2) + { + if (Body.WalkSpeed != 0) + Body.TranslateFacing(Target.Position, false); - if (PresetPowers[powerToUse].CooldownTime > 0f) - PresetPowers[powerToUse] = new Cooldown { CooldownTimer = new SecondsTickTimer(Body.World.Game, PresetPowers[powerToUse].CooldownTime), CooldownTime = PresetPowers[powerToUse].CooldownTime }; + CurrentAction = new PowerAction(Body, powerToUse, Target); - if (powerToUse == 96925 || - powerToUse == 223284) - PresetPowers[powerToUse] = new Cooldown { CooldownTimer = new SecondsTickTimer(Body.World.Game, 10f), CooldownTime = 10f }; - } - } - } - } + PresetPowers[powerToUse] = power switch + { + SummoningSkill => new Cooldown + { + CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f) + }, + MonsterAffixSkill monsterAffixSkill => new Cooldown + { + CooldownTimer = null, CooldownTime = monsterAffixSkill.CooldownTime + }, + _ => PresetPowers[powerToUse] + }; - else if (Body.GetObjectsInRange(50f).Count != 0) - { - if (_powerDelay.TimedOut) - { - _powerDelay = new SecondsTickTimer(Body.World.Game, 1.0f); + if (PresetPowers[powerToUse].CooldownTime > 0f) + PresetPowers[powerToUse] = new Cooldown + { + CooldownTimer = + new SecondsTickTimer(Body.World.Game, PresetPowers[powerToUse].CooldownTime), + CooldownTime = PresetPowers[powerToUse].CooldownTime + }; - if (AttackedBy != null) - PriorityTarget = AttackedBy; + if (powerToUse is 96925 or 223284) + PresetPowers[powerToUse] = new Cooldown + { CooldownTimer = new SecondsTickTimer(Body.World.Game, 10f), CooldownTime = 10f }; + } + else if (Body.WalkSpeed != 0) + { + if (Body.SNO.IsWoodwraithOrWasp()) + { + _logger.Trace( + $"{GetType().Name} $[underline white]${nameof(MoveToPointAction)}$[/]$ to target $[white]${Target.ActorType}$[/]$ [{Target.Position}]"); + CurrentAction = new MoveToPointAction( + Body, Target.Position + ); + } + else + { + _logger.Trace( + $"{GetType().Name} {nameof(MoveToTargetWithPathfindAction)} to target [{Target.ActorType}] {Target.SNO.ToString()}"); + CurrentAction = new MoveToTargetWithPathfindAction( + Body, + Target, + attackRange + Target.ActorData.Cylinder.Ax2, + powerToUse + ); + } + } + else + { + powerToUse = Body.SNO switch + { + ActorSno._a1dun_leor_firewall2 => 223284, + _ => powerToUse + }; + CurrentAction = new PowerAction(Body, powerToUse, Target); - if (PriorityTarget == null) - { - var targets = Body.GetActorsInRange(50f) - .Where(p => ((p is LorathNahr_NPC) && !p.Dead) - || ((p is CaptainRumford) && !p.Dead) - || (p is DesctructibleLootContainer && p.SNO.IsDoorOrBarricade()) - || ((p is Cain) && !p.Dead)) - .OrderBy((actor) => PowerMath.Distance2D(actor.Position, Body.Position)) - .ToArray(); + PresetPowers[powerToUse] = power switch + { + SummoningSkill => new Cooldown + { + CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f) + }, + MonsterAffixSkill skill => new Cooldown + { + CooldownTimer = null, CooldownTime = skill.CooldownTime + }, + _ => PresetPowers[powerToUse] + }; - if (targets.Length == 0) - { - targets = Body.GetActorsInRange(20f) - .Where(p => ((p is Monster) && !p.Dead) - || ((p is CaptainRumford) && !p.Dead) - ) - .OrderBy((actor) => PowerMath.Distance2D(actor.Position, Body.Position)) - .ToArray(); + if (PresetPowers[powerToUse].CooldownTime > 0f) + PresetPowers[powerToUse] = new Cooldown + { + CooldownTimer = + new SecondsTickTimer(Body.World.Game, PresetPowers[powerToUse].CooldownTime), + CooldownTime = PresetPowers[powerToUse].CooldownTime + }; + + if (powerToUse is 96925 or 223284) + PresetPowers[powerToUse] = new Cooldown + { CooldownTimer = new SecondsTickTimer(Body.World.Game, 10f), CooldownTime = 10f }; + } + } + + else if (Body.GetObjectsInRange(GameModsConfig.Instance.Monster.LookupRange).Count != 0) + { + if (!_powerDelay.TimedOut) return; + _powerDelay = new SecondsTickTimer(Body.World.Game, 1.0f); + + if (AttackedBy != null) + PriorityTarget = AttackedBy; + + if (PriorityTarget == null) + { + var targets = Body.GetActorsInRange(GameModsConfig.Instance.Monster.LookupRange) + .Where(p => ((p is LorathNahr_NPC) && !p.Dead) + || ((p is CaptainRumford) && !p.Dead) + || (p is DesctructibleLootContainer && p.SNO.IsDoorOrBarricade()) + || ((p is Cain) && !p.Dead)) + .OrderBy((actor) => PowerMath.Distance2D(actor.Position, Body.Position)) + .ToArray(); + + if (targets.Length == 0) + { + targets = Body.GetActorsInRange(20f) + .Where(p => ((p is Monster) && !p.Dead) + || ((p is CaptainRumford) && !p.Dead) + ) + .OrderBy((actor) => PowerMath.Distance2D(actor.Position, Body.Position)) + .ToArray(); - if (targets.Length == 0) - return; + if (targets.Length == 0) + return; - foreach (var monsterActor in targets.Where(tar => _target == null)) - if (monsterActor is Monster { Brain: MonsterBrain brain } monster && monsterActor != Body) - if (brain.AttackedBy != null) - _target = brain.AttackedBy; - } - else - { - _target = targets.First(); - } - foreach (var tar in targets) - if (tar is DesctructibleLootContainer && tar.SNO.IsDoorOrBarricade() && tar.SNO != ActorSno._trout_wagon_barricade) - { _target = tar; break; } - } - else - _target = PriorityTarget; + foreach (var monsterActor in targets.Where(tar => Target == null)) + if (monsterActor is Monster { Brain: MonsterBrain brain } monster && monsterActor != Body) + if (brain.AttackedBy != null) + Target = brain.AttackedBy; + } + else + { + Target = targets.First(); + } - int powerToUse = PickPowerToUse(); - if (powerToUse > 0) - { - PowerScript power = PowerLoader.CreateImplementationForPowerSNO(powerToUse); - power.User = Body; - if (_target == null) - { - /* - if (!this.Body.ActorSNO.Name.ToLower().Contains("woodwraith") && - !this.Body.ActorSNO.Name.ToLower().Contains("wasp")) - if (this.Body.Quality < 2) - { - this.CurrentAction = new MoveToPointWithPathfindAction(this.Body, RandomPosibleDirection(this.Body.CheckPointPosition, 3f, 8f, this.Body.World)); - return; - } - else - //*/ - return; - } - float attackRange = Body.ActorData.Cylinder.Ax2 + (power.EvalTag(PowerKeys.AttackRadius) > 0f ? (powerToUse == 30592 ? 10f : Math.Min((float)power.EvalTag(PowerKeys.AttackRadius), 35f)) : 35f); - float targetDistance = PowerMath.Distance2D(_target.Position, Body.Position); - if (targetDistance < attackRange + _target.ActorData.Cylinder.Ax2) - { - if (Body.WalkSpeed != 0) - Body.TranslateFacing(_target.Position, false); //columns and other non-walkable shit can't turn + foreach (var tar in targets) + if (tar is DesctructibleLootContainer && tar.SNO.IsDoorOrBarricade() && + tar.SNO != ActorSno._trout_wagon_barricade) + { + Target = tar; + break; + } + } + else + Target = PriorityTarget; - - Logger.Trace($"{GetType().Name} {nameof(PowerAction)} to target [{_target.ActorType}] {_target.SNO.ToString()}"); - // Logger.Trace("PowerAction to target"); - CurrentAction = new PowerAction(Body, powerToUse, _target); + int powerToUse = PickPowerToUse(); + if (powerToUse > 0) + { + PowerScript power = PowerLoader.CreateImplementationForPowerSNO(powerToUse); + power.User = Body; + if (Target == null) + { + /* + if (!this.Body.ActorSNO.Name.ToLower().Contains("woodwraith") && + !this.Body.ActorSNO.Name.ToLower().Contains("wasp")) + if (this.Body.Quality < 2) + { + this.CurrentAction = new MoveToPointWithPathfindAction(this.Body, RandomPosibleDirection(this.Body.CheckPointPosition, 3f, 8f, this.Body.World)); + return; + } + else + //*/ + return; + } - if (power is SummoningSkill) - PresetPowers[powerToUse] = new Cooldown { CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f) }; + float attackRange = Body.ActorData.Cylinder.Ax2 + (power.EvalTag(PowerKeys.AttackRadius) > 0f + ? (powerToUse == 30592 ? 10f : Math.Min((float)power.EvalTag(PowerKeys.AttackRadius), 35f)) + : 35f); + float targetDistance = PowerMath.Distance2D(Target.Position, Body.Position); + if (targetDistance < attackRange + Target.ActorData.Cylinder.Ax2) + { + if (Body.WalkSpeed != 0) + Body.TranslateFacing(Target.Position, + false); //columns and other non-walkable shit can't turn - if (power is MonsterAffixSkill monsterSkill) - PresetPowers[powerToUse] = new Cooldown { CooldownTimer = null, CooldownTime = monsterSkill.CooldownTime }; - if (PresetPowers[powerToUse].CooldownTime > 0f) - PresetPowers[powerToUse] = new Cooldown { CooldownTimer = new SecondsTickTimer(Body.World.Game, PresetPowers[powerToUse].CooldownTime), CooldownTime = PresetPowers[powerToUse].CooldownTime }; - } - else if (Body.WalkSpeed != 0) - { - if (Body.SNO.IsWoodwraithOrWasp()) - { - Logger.Trace($"{GetType().Name} {nameof(MoveToPointAction)} to target [{_target.Position}]"); + _logger.Trace( + $"{GetType().Name} {nameof(PowerAction)} to target [{Target.ActorType}] {Target.SNO.ToString()}"); + // Logger.Trace("PowerAction to target"); + CurrentAction = new PowerAction(Body, powerToUse, Target); - CurrentAction = new MoveToPointAction( - Body, _target.Position - ); - } - else - { - Logger.Trace($"{GetType().Name} {nameof(MoveToTargetWithPathfindAction)} to target [{_target.ActorType}] {_target.SNO.ToString()}"); + PresetPowers[powerToUse] = power switch + { + SummoningSkill => new Cooldown + { + CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f) + }, + MonsterAffixSkill monsterSkill => new Cooldown + { + CooldownTimer = null, CooldownTime = monsterSkill.CooldownTime + }, + _ => PresetPowers[powerToUse] + }; - CurrentAction = new MoveToTargetWithPathfindAction( - Body, - //( - _target,// + MovementHelpers.GetMovementPosition( - //new Vector3D(0, 0, 0), - //this.Body.WalkSpeed, - //MovementHelpers.GetFacingAngle(_target.Position, this.Body.Position), - //6 - //) - //) - attackRange + _target.ActorData.Cylinder.Ax2, - powerToUse - ); - } - } - } - } - } + if (PresetPowers[powerToUse].CooldownTime > 0f) + PresetPowers[powerToUse] = new Cooldown + { + CooldownTimer = new SecondsTickTimer(Body.World.Game, + PresetPowers[powerToUse].CooldownTime), + CooldownTime = PresetPowers[powerToUse].CooldownTime + }; + } + else if (Body.WalkSpeed != 0) + { + if (Body.SNO.IsWoodwraithOrWasp()) + { + _logger.Trace( + $"{GetType().Name} {nameof(MoveToPointAction)} to target [{Target.Position}]"); - else - { - //Logger.Trace("No enemies in range, return to master"); - if (Body.Position != Body.CheckPointPosition) - CurrentAction = new MoveToPointWithPathfindAction(Body, Body.CheckPointPosition); - } - } - } - public static Core.Types.Math.Vector3D RandomPossibleDirection(Core.Types.Math.Vector3D position, float minRadius, float maxRadius, MapSystem.World world) - { - float angle = (float)(FastRandom.Instance.NextDouble() * Math.PI * 2); - float radius = minRadius + (float)FastRandom.Instance.NextDouble() * (maxRadius - minRadius); - Core.Types.Math.Vector3D point = null; - int tryC = 0; - while (tryC < 100) - { - //break; - point = new Core.Types.Math.Vector3D(position.X + (float)Math.Cos(angle) * radius, - position.Y + (float)Math.Sin(angle) * radius, - position.Z); - if (world.CheckLocationForFlag(point, DiIiS_NA.Core.MPQ.FileFormats.Scene.NavCellFlags.AllowWalk)) - break; - tryC++; - } - return point; - } + CurrentAction = new MoveToPointAction( + Body, Target.Position + ); + } + else + { + _logger.Trace( + $"{GetType().Name} {nameof(MoveToTargetWithPathfindAction)} to target [{Target.ActorType}] {Target.SNO.ToString()}"); - public void FastAttack(Actor target, int skillSNO) - { - PowerScript power = PowerLoader.CreateImplementationForPowerSNO(skillSNO); - power.User = Body; - if (Body.WalkSpeed != 0) - Body.TranslateFacing(target.Position, false); //columns and other non-walkable shit can't turn - Logger.Trace($"{GetType().Name} {nameof(FastAttack)} {nameof(PowerAction)} to target [{_target.ActorType}] {_target.SNO.ToString()}"); - CurrentAction = new PowerAction(Body, skillSNO, target); + CurrentAction = new MoveToTargetWithPathfindAction( + Body, + //( + Target, // + MovementHelpers.GetMovementPosition( + //new Vector3D(0, 0, 0), + //this.Body.WalkSpeed, + //MovementHelpers.GetFacingAngle(_target.Position, this.Body.Position), + //6 + //) + //) + attackRange + Target.ActorData.Cylinder.Ax2, + powerToUse + ); + } + } + } + } - if (power is SummoningSkill) - PresetPowers[skillSNO] = new Cooldown { CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f) }; + else + { + //Logger.Trace("No enemies in range, return to master"); + if (Body.Position != Body.CheckPointPosition) + CurrentAction = new MoveToPointWithPathfindAction(Body, Body.CheckPointPosition); + } + } - if (power is MonsterAffixSkill monsterAffixSkill) - PresetPowers[skillSNO] = new Cooldown { CooldownTimer = null, CooldownTime = monsterAffixSkill.CooldownTime }; + public static Core.Types.Math.Vector3D RandomPossibleDirection(Core.Types.Math.Vector3D position, + float minRadius, float maxRadius, MapSystem.World world) + { + float angle = (float)(FastRandom.Instance.NextDouble() * Math.PI * 2); + float radius = minRadius + (float)FastRandom.Instance.NextDouble() * (maxRadius - minRadius); + Core.Types.Math.Vector3D point = null; + int tryC = 0; + while (tryC < 100) + { + //break; + point = new Core.Types.Math.Vector3D(position.X + (float)Math.Cos(angle) * radius, + position.Y + (float)Math.Sin(angle) * radius, + position.Z); + if (world.CheckLocationForFlag(point, DiIiS_NA.Core.MPQ.FileFormats.Scene.NavCellFlags.AllowWalk)) + break; + tryC++; + } - if (PresetPowers[skillSNO].CooldownTime > 0f) - PresetPowers[skillSNO] = new Cooldown { CooldownTimer = new SecondsTickTimer(Body.World.Game, PresetPowers[skillSNO].CooldownTime), CooldownTime = PresetPowers[skillSNO].CooldownTime }; - } + return point; + } - protected virtual int PickPowerToUse() - { - if (!_warnedNoPowers && PresetPowers.Count == 0) - { - Logger.Warn($"Monster $[red]$\"{Body.Name}\"$[/]$ has no usable powers. {_mpqPowerCount} are defined in mpq data."); - _warnedNoPowers = true; - return -1; - } + public void FastAttack(Actor target, int skillSno) + { + PowerScript power = PowerLoader.CreateImplementationForPowerSNO(skillSno); + power.User = Body; + if (Body.WalkSpeed != 0) + Body.TranslateFacing(target.Position, false); //columns and other non-walkable shit can't turn + _logger.Trace( + $"{GetType().Name} {nameof(FastAttack)} {nameof(PowerAction)} to target [{Target.ActorType}] {Target.SNO.ToString()}"); + CurrentAction = new PowerAction(Body, skillSno, target); - // randomly used an implemented power - if (PresetPowers.Count <= 0) return -1; - - //int power = this.PresetPowers[RandomHelper.Next(this.PresetPowers.Count)].Key; - var availablePowers = PresetPowers.Where(p => (p.Value.CooldownTimer == null || p.Value.CooldownTimer.TimedOut) && PowerLoader.HasImplementationForPowerSNO(p.Key)).Select(p => p.Key).ToList(); - if (availablePowers.Where(p => p != 30592).TryPickRandom(out var selectedPower)) - { - return selectedPower; - } + PresetPowers[skillSno] = power switch + { + SummoningSkill => new Cooldown { CooldownTimer = null, CooldownTime = (Body is Boss ? 15f : 7f) }, + MonsterAffixSkill monsterAffixSkill => new Cooldown + { + CooldownTimer = null, CooldownTime = monsterAffixSkill.CooldownTime + }, + _ => PresetPowers[skillSno] + }; - if (availablePowers.Contains(30592)) - return 30592; // melee attack + if (PresetPowers[skillSno].CooldownTime > 0f) + PresetPowers[skillSno] = new Cooldown + { + CooldownTimer = new SecondsTickTimer(Body.World.Game, PresetPowers[skillSno].CooldownTime), + CooldownTime = PresetPowers[skillSno].CooldownTime + }; + } - // no usable power - return -1; - } + protected virtual int PickPowerToUse() + { + if (!_warnedNoPowers && PresetPowers.Count == 0) + { + _logger.Warn( + $"Monster $[red]$\"{Body.Name}\"$[/]$ has no usable powers. {_mpqPowerCount} are defined in mpq data."); + _warnedNoPowers = true; + return -1; + } - public void AddPresetPower(int powerSNO) - { - if (PresetPowers.ContainsKey(powerSNO)) - { - Logger.Debug($"Monster $[red]$\"{Body.Name}\"$[/]$ already has power {powerSNO}."); - // Logger.MethodTrace("power sno {0} already defined for monster \"{1}\"", - //powerSNO, this.Body.ActorSNO.Name); - return; - } + // randomly used an implemented power + if (PresetPowers.Count <= 0) return -1; - PresetPowers.Add(powerSNO, - PresetPowers.ContainsKey(30592) //if can cast melee - ? new Cooldown { CooldownTimer = null, CooldownTime = 5f } - : new Cooldown - { CooldownTimer = null, CooldownTime = 1f + (float)FastRandom.Instance.NextDouble() }); - } + //int power = this.PresetPowers[RandomHelper.Next(this.PresetPowers.Count)].Key; + var availablePowers = PresetPowers + .Where(p => (p.Value.CooldownTimer == null || p.Value.CooldownTimer.TimedOut) && + PowerLoader.HasImplementationForPowerSNO(p.Key)).Select(p => p.Key).ToList(); + if (availablePowers.Where(p => p != 30592).TryPickRandom(out var selectedPower)) + { + return selectedPower; + } - public void RemovePresetPower(int powerSNO) - { - if (PresetPowers.ContainsKey(powerSNO)) - { - PresetPowers.Remove(powerSNO); - } - } - } -} + if (availablePowers.Contains(30592)) + return 30592; // melee attack + + // no usable power + return -1; + } + + public void AddPresetPower(int powerSno) + { + if (PresetPowers.ContainsKey(powerSno)) + { + _logger.Debug($"Monster $[red]$\"{Body.Name}\"$[/]$ already has power {powerSno}."); + // Logger.MethodTrace("power sno {0} already defined for monster \"{1}\"", + //powerSNO, this.Body.ActorSNO.Name); + return; + } + + PresetPowers.Add(powerSno, + PresetPowers.ContainsKey(30592) //if can cast melee + ? new Cooldown { CooldownTimer = null, CooldownTime = 5f } + : new Cooldown + { CooldownTimer = null, CooldownTime = 1f + (float)FastRandom.Instance.NextDouble() }); + } + + public void RemovePresetPower(int powerSno) + { + if (PresetPowers.ContainsKey(powerSno)) + { + PresetPowers.Remove(powerSno); + } + } + } +} \ No newline at end of file diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Boss.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Boss.cs index 282a8f2..e5f26fc 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Boss.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Boss.cs @@ -4,6 +4,7 @@ using DiIiS_NA.GameServer.GSSystem.AISystem.Brains; using DiIiS_NA.GameServer.MessageSystem; using DiIiS_NA.Core.Logging; using DiIiS_NA.Core.MPQ.FileFormats; +using DiIiS_NA.D3_GameServer; namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations { @@ -73,9 +74,9 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations //this.Attributes[GameAttribute.Immune_To_Charm] = true; Attributes[GameAttributes.using_Bossbar] = true; Attributes[GameAttributes.InBossEncounter] = true; - Attributes[GameAttributes.Hitpoints_Max] *= GameServerConfig.Instance.BossHealthMultiplier; - Attributes[GameAttributes.Damage_Weapon_Min, 0] *= GameServerConfig.Instance.BossDamageMultiplier; - Attributes[GameAttributes.Damage_Weapon_Delta, 0] *= GameServerConfig.Instance.BossDamageMultiplier; + Attributes[GameAttributes.Hitpoints_Max] *= GameModsConfig.Instance.Boss.HealthMultiplier; + Attributes[GameAttributes.Damage_Weapon_Min, 0] *= GameModsConfig.Instance.Boss.DamageMultiplier; + Attributes[GameAttributes.Damage_Weapon_Delta, 0] *= GameModsConfig.Instance.Boss.DamageMultiplier; Attributes[GameAttributes.Hitpoints_Cur] = Attributes[GameAttributes.Hitpoints_Max_Total]; Attributes[GameAttributes.TeamID] = 10; diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/LegendaryChest.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/LegendaryChest.cs index a0eed33..7727930 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/LegendaryChest.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/LegendaryChest.cs @@ -52,7 +52,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations World.SpawnRandomEquip(player, player, FastRandom.Instance.Next(100) < chance ? LootManager.Epic : LootManager.Rare, player.Level); - var toon = player.Toon.DBToon; + var toon = player.Toon.DbToon; toon.ChestsOpened++; World.Game.GameDbSession.SessionUpdate(toon); } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/LootContainer.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/LootContainer.cs index 3962739..b726851 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/LootContainer.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/LootContainer.cs @@ -94,7 +94,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations if (haveDrop) { - var dropRates = World.Game.IsHardcore ? LootManager.GetSeasonalDropRates((int)Quality, Program.MaxLevel) : LootManager.GetDropRates((int)Quality, Program.MaxLevel); + var dropRates = World.Game.IsHardcore ? LootManager.GetSeasonalDropRates((int)Quality, Program.MAX_LEVEL) : LootManager.GetDropRates((int)Quality, Program.MAX_LEVEL); foreach (var rate in dropRates) foreach (var plr in GetPlayersInRange(30)) { diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Monsters/Bosses.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Monsters/Bosses.cs index 465ef36..1ba12a8 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Monsters/Bosses.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Monsters/Bosses.cs @@ -2,6 +2,7 @@ using DiIiS_NA.GameServer.Core.Types.TagMap; using DiIiS_NA.GameServer.GSSystem.MapSystem; using DiIiS_NA.GameServer.MessageSystem; +using Microsoft.Extensions.Logging; namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Monsters { @@ -27,13 +28,9 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Monsters public override int Quality { - get - { - return (int)DiIiS_NA.Core.MPQ.FileFormats.SpawnType.Boss; - } + get => (int)DiIiS_NA.Core.MPQ.FileFormats.SpawnType.Boss; set { - } } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Monster.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Monster.cs index 6a1d9ad..813d9cf 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Monster.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Monster.cs @@ -6,6 +6,7 @@ using GameBalance = DiIiS_NA.Core.MPQ.FileFormats.GameBalance; using DiIiS_NA.GameServer.GSSystem.ObjectsSystem; using DiIiS_NA.Core.Logging; using DiIiS_NA.Core.MPQ.FileFormats; +using DiIiS_NA.D3_GameServer; using DiIiS_NA.GameServer.GSSystem.TickerSystem; using DiIiS_NA.GameServer.MessageSystem; using DiIiS_NA.GameServer.Core.Types.SNO; @@ -17,12 +18,22 @@ using DiIiS_NA.GameServer.GSSystem.AISystem.Brains; using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations; using DiIiS_NA.D3_GameServer.Core.Types.SNO; using World = DiIiS_NA.GameServer.GSSystem.MapSystem.World; +using DiIiS_NA.Core.Helpers.Math; +using DiIiS_NA.LoginServer.Toons; +using static DiIiS_NA.Core.MPQ.FileFormats.Monster; +using D3.Store; +using DiIiS_NA.GameServer.GSSystem.AISystem; +using DiIiS_NA.GameServer.GSSystem.MapSystem; +using Microsoft.EntityFrameworkCore.Metadata; +using static DiIiS_NA.Core.Logging.Logger; +using System.IO; +using System.Net.NetworkInformation; namespace DiIiS_NA.GameServer.GSSystem.ActorSystem { public class Monster : Living, IUpdateable { - private static readonly Logger Logger = LogManager.CreateLogger(nameof(Monster)); + private static readonly Logger Logger = LogManager.CreateLogger(); public override ActorType ActorType => ActorType.Monster; public TickTimer DestroyTimer { get; } @@ -39,9 +50,9 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem public int LoreSnoId => Monster.IsValid ? ((MonsterFF)Monster.Target).SNOLore : -1; - public int MonsterType => Monster.IsValid ? (int)((MonsterFF)Monster.Target).Type : -1; - - public float HpMultiplier => Monster.IsValid ? (1f + ((MonsterFF)Monster.Target).AttributeModifiers[4]) : 1f; + public int MonsterTypeValue => Monster.IsValid ? (int)((MonsterFF)Monster.Target).Type : -1; + public MonsterType MonsterType => (MonsterType)(((MonsterFF)Monster.Target)?.Type ?? MonsterType.Unknown); + public float HpMultiplier => Monster.IsValid ? (1f + ((MonsterFF)Monster.Target).AttributeModifiers[4]) : 1f; public float DmgMultiplier => Monster.IsValid ? (1f + ((MonsterFF)Monster.Target).AttributeModifiers[55]) : 1f; public Vector3D BasePoint { get; set; } @@ -70,7 +81,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem //WalkSpeed /= 2f; Brain = new MonsterBrain(this); - Attributes[GameAttributes.Attacks_Per_Second] = 1.2f; + Attributes[GameAttributes.Attacks_Per_Second] = GameModsConfig.Instance.Monster.AttacksPerSecond;// 1.2f; UpdateStats(); } @@ -80,54 +91,187 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem #if DEBUG string monster = "monster"; if (this is Boss) monster = "boss"; - Logger.MethodTrace($"Player {player.Name} targeted {monster} {GetType().Name}."); + Logger.MethodTrace($"Player {player.Name} targeted $[underline]${monster}$[/]$ {GetType().Name}."); #endif } public void UpdateStats() { - var monsterLevels = (GameBalance)DiIiS_NA.Core.MPQ.MPQStorage.Data.Assets[SNOGroup.GameBalance][19760].Data; + // TODO: Level up is getting harder from level 3+. 1 seems stable. check the difficulty. + // TODO: Level up is getting harder from level 3+. 1 seems stable. check the difficulty. + // TODO: Level up is getting harder from level 3+. 1 seems stable. check the difficulty. + + var monsterLevels = (GameBalance)DiIiS_NA.Core.MPQ.MPQStorage.Data.Assets[SNOGroup.GameBalance][19760].Data; bool fullHp = (Math.Abs(Attributes[GameAttributes.Hitpoints_Cur] - Attributes[GameAttributes.Hitpoints_Max_Total]) < Globals.FLOAT_TOLERANCE); Attributes[GameAttributes.Level] = World.Game.MonsterLevel; //this.Attributes[GameAttribute.Hitpoints_Max] = (int)monsterLevels.MonsterLevel[this.World.Game.MonsterLevel - 1].HPMin * (int)this.HPMultiplier * (int)this.World.Game.HPModifier; int monsterLevel = 1; monsterLevel = World.Game.ConnectedPlayers.Length > 1 ? World.Game.ConnectedPlayers[0].Level : World.Game.InitialMonsterLevel; - - Attributes[GameAttributes.Hitpoints_Max] = (int)((int)monsterLevels.MonsterLevel[monsterLevel].HPMin + DiIiS_NA.Core.Helpers.Math.RandomHelper.Next(0, (int)monsterLevels.MonsterLevel[monsterLevel].HPDelta) * HpMultiplier * World.Game.HpModifier); - Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative] = ((int)World.Game.ConnectedPlayers.Length + 1) * 1.5f; - Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative] *= GameServerConfig.Instance.RateMonsterHP; - if (World.Game.ConnectedPlayers.Length > 1) - Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative] = Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative];// / 2f; - var hpMax = Attributes[GameAttributes.Hitpoints_Max]; - var hpTotal = Attributes[GameAttributes.Hitpoints_Max_Total]; - float damageMin = monsterLevels.MonsterLevel[World.Game.MonsterLevel].Dmg * DmgMultiplier;// * 0.5f; - float damageDelta = damageMin; - Attributes[GameAttributes.Damage_Weapon_Min, 0] = damageMin * World.Game.DmgModifier * GameServerConfig.Instance.RateMonsterDMG; - Attributes[GameAttributes.Damage_Weapon_Delta, 0] = damageDelta; - - if (monsterLevel > 30) + var connectedPlayers = World.Game.ConnectedPlayers.ToArray(); + double maxUsersHealth = 1f; + double deltaDamageUsers = 1f; + int userLevelAverage = 1; + + if (connectedPlayers.Any()) { - Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative] = Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative];// * 0.5f; - Attributes[GameAttributes.Damage_Weapon_Min, 0] = damageMin * World.Game.DmgModifier * GameServerConfig.Instance.RateMonsterDMG;// * 0.2f; - Attributes[GameAttributes.Damage_Weapon_Delta, 0] = damageDelta; - } - if (monsterLevel > 60) - { - Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative] = Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative];// * 0.7f; - Attributes[GameAttributes.Damage_Weapon_Min, 0] = damageMin * World.Game.DmgModifier * GameServerConfig.Instance.RateMonsterDMG;// * 0.15f; - //this.Attributes[GameAttribute.Damage_Weapon_Delta, 0] = DamageDelta * 0.5f; + maxUsersHealth = connectedPlayers.Average(x => x.Attributes[GameAttributes.Hitpoints_Max]); + deltaDamageUsers = connectedPlayers.Average(x => x.Attributes[GameAttributes.Damage_Delta]); + userLevelAverage = (int)connectedPlayers.Average(x => x.Level); + Logger.MethodTrace($"$[yellow]${connectedPlayers.Length}$[/]$ $[green]$players online$[/]$: $[blue dim]${maxUsersHealth}$[/]$ $[bold]$avg. max health$[/]$ / $[blue dim italic]${deltaDamageUsers}$[/]$ $[bold]$avg. delta damage$[/]$"); } - _nativeHp = Attributes[GameAttributes.Hitpoints_Max_Total]; - _nativeDmg = Attributes[GameAttributes.Damage_Weapon_Min, 0]; - //if (full_hp) - Attributes[GameAttributes.Hitpoints_Cur] = Attributes[GameAttributes.Hitpoints_Max_Total]; + var difficulty = World.Game.Difficulty; + var maxHP = (monsterLevels.MonsterLevel[monsterLevel].HPMin + + RandomHelper.NextFloat(0f, monsterLevels.MonsterLevel[monsterLevel].HPDelta)) * + HpMultiplier * World.Game.HpModifier; + var bonus = CalculateLevelAdjustment(LevelAdjustmentEnum.LinearScaling, difficulty, connectedPlayers); + + Attributes[GameAttributes.Hitpoints_Max] = maxHP; + Attributes[GameAttributes.Hitpoints_Max_Percent_Bonus_Multiplicative] = bonus; + + var baseHp = Attributes[GameAttributes.Hitpoints_Max]; + var baseDamage = Attributes[GameAttributes.Damage_Weapon_Min, 0]; + + // Apply calculated scaling + baseHp *= bonus; + baseDamage *= bonus; + + // Apply configuration modifiers + baseHp *= GameModsConfig.Instance.Monster.HealthMultiplier; + baseDamage *= GameModsConfig.Instance.Monster.DamageMultiplier; + + // Assign modified values + Attributes[GameAttributes.Hitpoints_Max_Total] = baseHp; + Attributes[GameAttributes.Damage_Weapon_Min, 0] = baseDamage; + //if (full_hp) + Attributes[GameAttributes.Hitpoints_Cur] = Attributes[GameAttributes.Hitpoints_Max_Total]; Attributes.BroadcastChangedIfRevealed(); } - int _bleedFirstTick = 0; + enum LevelAdjustmentEnum { LinearScaling, DiminishedReturns, CurveScaling, LinearScalingAndDiminishedReturnsAfterThreshold } + + private float CalculateLevelAdjustment(LevelAdjustmentEnum levelAdjustment, int difficulty = 0, params Player[] players) + { + var playersStats = players.Select(s => + new + { + s.Attributes, + TotalLevel = s.Level + s.ParagonLevel * 1.05f, + Health = s.Attributes[GameAttributes.Hitpoints_Max], + Damage = s.Attributes[GameAttributes.Damage_Weapon_Min, 0], + Toughness = s.Attributes[GameAttributes.Armor_Total], + DPS = s.Attributes[GameAttributes.DPS] + } + ).ToArray(); + var monstersNearbyStats = players.WhereNearbyOf(World.Monsters.ToArray(), s => s.Visible && s.Alive && s.Attributes[GameAttributes.Hitpoints_Max] * 0.8 > Attributes[GameAttributes.Hitpoints_Cur], 120f, 1f).ToArray(); + var monsterStats = monstersNearbyStats.Select(s => + new + { + s.Attributes, + Health = s.Attributes[GameAttributes.Hitpoints_Max], + Damage = s.Attributes[GameAttributes.Damage_Weapon_Min, 0], + Toughness = s.Attributes[GameAttributes.Armor_Total], + DPS = s.Attributes[GameAttributes.DPS] + } + ).ToArray(); + + // Define configuration constants + // This is the multiplier for linear scaling. It determines how much the monster's level increases for each player level. + // If you increase this value, monsters will become stronger faster as player levels increase. + const float linearMultiplierConfig = 0.025f; + + // This is the multiplier for diminished returns scaling. It determines how much the monster's level increases for each player level, + // but the increase becomes smaller as player levels get higher. If you increase this value, monsters will become stronger faster at lower player levels. + const float diminishedMultiplierConfig = 0.1f; + + // This is the base value for diminished returns scaling. It's the starting point for the monster's level before any scaling is applied. + // If you increase this value, monsters will start off stronger before any player level scaling is applied. + const float diminishedBaseConfig = 1.0f; + + // This is the multiplier for curve scaling. It determines how much the monster's level increases for each player level, + // but the increase becomes larger as player levels get higher. If you increase this value, monsters will become stronger faster at higher player levels. + const float curveMultiplierConfig = 0.1f; + + // This is the base value for curve scaling. It's the starting point for the monster's level before any scaling is applied. + // If you increase this value, monsters will start off stronger before any player level scaling is applied. + const float curveBaseConfig = 30.0f; + + // This is the exponent for curve scaling. It determines the shape of the curve for how much the monster's level increases for each player level. + // If you increase this value, the curve will be steeper, meaning monsters will become much stronger at higher player levels. + const float curveExponentConfig = 0.1f; + + // This is the multiplier for linear scaling after a certain threshold. It determines how much the monster's level increases for each player level + // after the player level has reached a certain threshold. If you increase this value, monsters will become stronger faster after player levels reach the threshold. + const float linearMultiplierThresholdConfig = 0.005f; + + // This is the multiplier for log scaling. It determines how much the monster's level increases for each player level, + // but the increase becomes smaller as player levels get higher. If you increase this value, monsters will become stronger faster at lower player levels. + const float logMultiplierConfig = 0.1f; + + // This is the threshold for linear scaling. It determines the player level at which linear scaling starts to apply. + // If you increase this value, linear scaling will start to apply at higher player levels. + const float thresholdConfig = 40.0f; + + // This is the ratio for DPS (Damage Per Second) scaling. It determines how much the monster's level increases for each unit of player DPS. + // If you increase this value, monsters will become stronger faster as player DPS increases. + const float dpsRatioConfig = 1.2f; + + // This is the ratio for toughness scaling. It determines how much the monster's level increases for each unit of player toughness. + // If you increase this value, monsters will become stronger faster as player toughness increases. + const float toughnessRatioConfig = 0.1f; + + // Define variables for average user and monster stats + // float avgUserLevel = playersStats.Average(s => s.TotalLevel); + // float avgUserDPS = playersStats.Average(s => s.DPS); + // float avgUserToughness = playersStats.Average(s => s.Toughness); + //float avgMonsterDPS = playersStats.Average(s => s.DPS); + // float avgMonsterToughness = monsterStats.Average(s => s.Toughness); + //var tierMultiplier = GetMonsterTierMultiplier(); + float avgUserLevel = 1f, avgUserDPS = 1f, avgUserToughness = 1f, avgMonsterDPS = 1f, avgMonsterToughness = 1f, tierMultiplier = 1f; + + if (playersStats.Any()) + { + avgUserLevel = playersStats.Average(s => s.TotalLevel); + avgUserDPS = playersStats.Average(s => s.DPS); + avgUserToughness = playersStats.Average(s => s.Toughness); + } + if (monsterStats.Any()) + { + avgMonsterDPS = playersStats.Average(s => s.DPS); + avgMonsterToughness = monsterStats.Average(s => s.Toughness); + tierMultiplier = GetMonsterTierMultiplier(); + } + float LevelScaling() => 1.0f + 0.1f * MathF.Log10(avgUserLevel + 1) * tierMultiplier; + float DiminishedReturns() => diminishedBaseConfig + diminishedMultiplierConfig * avgUserLevel; + float CurveScaling() => curveBaseConfig * MathF.Pow(avgUserLevel, curveExponentConfig) * curveMultiplierConfig; + float LinearScalingAndDiminishedReturnsAfterThreshold() => MathF.Max(1.0f, MathF.Min(1.5f, logMultiplierConfig * MathF.Log10(avgUserLevel + 1) + (avgUserLevel - thresholdConfig) * linearMultiplierThresholdConfig) * tierMultiplier); + + return levelAdjustment switch + { + LevelAdjustmentEnum.LinearScaling => LevelScaling(), + LevelAdjustmentEnum.DiminishedReturns => DiminishedReturns(), + LevelAdjustmentEnum.CurveScaling => CurveScaling(), + LevelAdjustmentEnum.LinearScalingAndDiminishedReturnsAfterThreshold => LinearScalingAndDiminishedReturnsAfterThreshold(), + _ => LinearScalingAndDiminishedReturnsAfterThreshold() + }; + } + + private float GetMonsterTierMultiplier() + { + return MonsterType switch + { + MonsterType.Beast => 1.1f, + MonsterType.Demon => 1.15f, + MonsterType.Human => 1.25f, + MonsterType.Undead => 1.4f, // Steeper jump here + _ => 1.0f, + }; + } + + + int _bleedFirstTick = 0; int _caltropsFirstTick = 0; public void Update(int tickCounter) @@ -187,14 +331,12 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem lock (_adjustLock) { int count = player.World.Game.Players.Count; - if (count > 0 && _adjustedPlayers != count) - { - Attributes[GameAttributes.Damage_Weapon_Min, 0] = _nativeDmg * (1f + (0.05f * (count - 1) * player.World.Game.Difficulty)); - Attributes[GameAttributes.Hitpoints_Max] = _nativeHp * (1f + ((0.75f + (0.1f * player.World.Game.Difficulty)) * (count - 1))); - Attributes[GameAttributes.Hitpoints_Cur] = Attributes[GameAttributes.Hitpoints_Max_Total]; - Attributes.BroadcastChangedIfRevealed(); - _adjustedPlayers = count; - } + if (count <= 0 || _adjustedPlayers == count) return true; + Attributes[GameAttributes.Damage_Weapon_Min, 0] = _nativeDmg * (1f + (0.05f * (count - 1) * player.World.Game.Difficulty)); + Attributes[GameAttributes.Hitpoints_Max] = _nativeHp * (1f + ((0.75f + (0.1f * player.World.Game.Difficulty)) * (count - 1))); + Attributes[GameAttributes.Hitpoints_Cur] = Attributes[GameAttributes.Hitpoints_Max_Total]; + Attributes.BroadcastChangedIfRevealed(); + _adjustedPlayers = count; } return true; diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/ActEnum.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/ActEnum.cs new file mode 100644 index 0000000..adc99ec --- /dev/null +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/ActEnum.cs @@ -0,0 +1,11 @@ +namespace DiIiS_NA.GameServer.GSSystem.GameSystem; + +public enum ActEnum +{ + Act1 = 0, + Act2 = 100, + Act3 = 200, + Act4 = 300, + Act5 = 400, + OpenWorld = 3000 +} \ No newline at end of file diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GSBackend.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GSBackend.cs index de09d86..56ffda6 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GSBackend.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GSBackend.cs @@ -26,7 +26,7 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem private bool SenderMessageReceived(byte[] data) { string msg = ""; - if (data != null && data.Length > 0) msg = Encoding.UTF8.GetString(data); + if (data is { Length: > 0 }) msg = Encoding.UTF8.GetString(data); Logger.Debug("Message from Battle.net: {0}", msg); var message = msg.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); @@ -74,8 +74,11 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem string backEndIp = GameServerConfig.Instance.BindIP; int backEndPort = GameServerConfig.Instance.Port; bool pvp = false; - if (!pvp) + Logger.Info("We are here"); + if (!pvp){ + Logger.Info("Ip: {0}|{1}", backEndIp, backEndPort); RegisterGameServer(backEndIp, backEndPort); + } else RegisterPvPGameServer(backEndIp, backEndPort); return true; diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/Game.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/Game.cs index f952a83..6db988e 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/Game.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/Game.cs @@ -31,27 +31,18 @@ using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Hirelings; using DiIiS_NA.GameServer.GSSystem.GeneratorsSystem; using DiIiS_NA.GameServer.GSSystem.AISystem.Brains; using System.Diagnostics; -using System.Runtime.CompilerServices; using DiIiS_NA.Core.MPQ.FileFormats; +using DiIiS_NA.D3_GameServer; using DiIiS_NA.D3_GameServer.Core.Types.SNO; using DiIiS_NA.D3_GameServer.GSSystem.GameSystem; using Actor = DiIiS_NA.GameServer.GSSystem.ActorSystem.Actor; using Monster = DiIiS_NA.GameServer.GSSystem.ActorSystem.Monster; using Scene = DiIiS_NA.GameServer.GSSystem.MapSystem.Scene; using World = DiIiS_NA.GameServer.GSSystem.MapSystem.World; +using System.Runtime.CompilerServices; namespace DiIiS_NA.GameServer.GSSystem.GameSystem { - public enum ActEnum - { - Act1 = 0, - Act2 = 100, - Act3 = 200, - Act4 = 300, - Act5 = 400, - OpenWorld = 3000 - } - public class Game : IMessageConsumer { private static readonly Logger Logger = LogManager.CreateLogger(); @@ -66,6 +57,8 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem /// public ConcurrentDictionary Players { get; private set; } + public Player FirstPlayer() => Players.Values.First(); + public ImmutableArray ConnectedPlayers => Players .Where(s => s.Value != null && s.Key.Connection.IsOpen() && !s.Key.IsLoggingOut) .Select(s => s.Value).ToImmutableArray(); @@ -145,8 +138,8 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem public int AcceptedPlayers; }; - public readonly Dictionary> OnLoadWorldActions = new(); - public readonly Dictionary> OnLoadSceneActions = new(); + public readonly Dictionary> OnLoadWorldActions = new(); + public readonly Dictionary> OnLoadSceneActions = new(); public BossEncounter CurrentEncounter = new() { SnoId = -1, Activated = false, AcceptedPlayers = 0 }; @@ -190,9 +183,10 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem /// Current quest SNOid. /// public int CurrentQuest = -1; - public int CurrentSideQuest = -1; + public bool IsCurrentOpenWorld => CurrentQuest == 312429; + /// /// Current quest step SNOid. /// @@ -667,7 +661,7 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem /// The new player. public void Enter(Player joinedPlayer) { - if (IsHardcore && !joinedPlayer.Toon.DBToon.isHardcore) + if (IsHardcore && !joinedPlayer.Toon.DbToon.isHardcore) { return; } @@ -1276,18 +1270,28 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem public void SetDifficulty(int diff) { - Difficulty = diff; - if (Difficulty < 0) Difficulty = 0; - if (Difficulty > 19) Difficulty = 19; + Difficulty = Math.Clamp(diff, 0, 19); diff++; if (diff > 0) { var handicapLevels = (GameBalance)MPQStorage.Data.Assets[SNOGroup.GameBalance][256027].Data; - HpModifier = handicapLevels.HandicapLevelTables[diff].HPMod; - DmgModifier = handicapLevels.HandicapLevelTables[diff].DmgMod; - XpModifier = (1f + handicapLevels.HandicapLevelTables[diff].XPMod); - GoldModifier = (1f + handicapLevels.HandicapLevelTables[diff].GoldMod); + HpModifier = handicapLevels.HandicapLevelTables[diff].HPMod * GameModsConfig.Instance.Rate.HealthByDifficulty[Difficulty] + * GameModsConfig.Instance.Monster.HealthMultiplier; + DmgModifier = handicapLevels.HandicapLevelTables[diff].DmgMod + * GameModsConfig.Instance.Rate.GetDamageByDifficulty(diff) + * GameModsConfig.Instance.Monster.DamageMultiplier; + XpModifier = (1f + handicapLevels.HandicapLevelTables[diff].XPMod) * GameModsConfig.Instance.Rate.Experience; + GoldModifier = (1f + handicapLevels.HandicapLevelTables[diff].GoldMod * GameModsConfig.Instance.Rate.Gold); } + else + { + HpModifier = GameModsConfig.Instance.Rate.HealthByDifficulty[diff] * GameModsConfig.Instance.Monster.HealthMultiplier; + DmgModifier = GameModsConfig.Instance.Rate.GetDamageByDifficulty(diff) * GameModsConfig.Instance.Monster.DamageMultiplier; + XpModifier = 1f + GameModsConfig.Instance.Rate.Experience; + GoldModifier = (1f * GameModsConfig.Instance.Rate.Gold); + } + + Logger.Info($"$[italic]$Updated Game #$[underline]${GameId}$[/]$ difficulty to {diff}.$[/]$"); foreach (var wld in _worlds) foreach (var monster in wld.Value.Monsters) @@ -1336,13 +1340,13 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem target.InGameClient.SendMessage(new NewPlayerMessage { PlayerIndex = joinedPlayer.PlayerIndex, - NewToonId = (long)joinedPlayer.Toon.D3EntityID.IdLow, + NewToonId = (long)joinedPlayer.Toon.D3EntityId.IdLow, GameAccountId = new GameAccountHandle() { ID = (uint)joinedPlayer.Toon.GameAccount.BnetEntityId.Low, Program = 0x00004433, Region = 1 }, ToonName = joinedPlayer.Toon.Name, Team = 0x00000002, Class = joinedPlayer.ClassSno, - snoActorPortrait = joinedPlayer.Toon.DBToon.Cosmetic4, + snoActorPortrait = joinedPlayer.Toon.DbToon.Cosmetic4, Level = joinedPlayer.Toon.Level, AltLevel = (ushort)joinedPlayer.Toon.ParagonLevel, HighestHeroSoloRiftLevel = 0, @@ -1570,9 +1574,8 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem //handling quest triggers - if (QuestProgress.QuestTriggers.ContainsKey(levelArea)) //EnterLevelArea + if (QuestProgress.QuestTriggers.TryGetValue(levelArea, out var trigger)) //EnterLevelArea { - var trigger = QuestProgress.QuestTriggers[levelArea]; if (trigger.TriggerType == QuestStepObjectiveType.EnterLevelArea) { try @@ -1645,7 +1648,7 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem //Берем каина var firstPoint = new Vector3D(120.92718f, 121.26151f, 0.099973306f); var secondPoint = new Vector3D(120.73298f, 160.61829f, 0.31863004f); - var sceletonPoint = new Vector3D(120.11514f, 140.77332f, 0.31863004f); + var sketonPosition = new Vector3D(120.11514f, 140.77332f, 0.31863004f); var firstfacingAngle = ActorSystem.Movement.MovementHelpers.GetFacingAngle(cainRun, firstPoint); @@ -1666,9 +1669,9 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem { foreach (var skeleton in skeletons) { - skeleton.Move(sceletonPoint, + skeleton.Move(sketonPosition, ActorSystem.Movement.MovementHelpers.GetFacingAngle(skeleton, - sceletonPoint)); + sketonPosition)); } cainRun.Move(secondPoint, secondfacingAngle); diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GameManager.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GameManager.cs index f703915..2cf1f0a 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GameManager.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GameManager.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using NHibernate.Util; namespace DiIiS_NA.GameServer.GSSystem.GameSystem { @@ -20,8 +21,8 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem public static Game CreateGame(int gameId, int initialLevel) { - if (Games.ContainsKey(gameId)) - return Games[gameId]; + if (Games.TryGetValue(gameId, out var createdGame)) + return createdGame; var game = new Game(gameId, initialLevel); Games.Add(gameId, game); @@ -35,84 +36,98 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem public static int GetIdByGame(Game game) { - return !Games.ContainsValue(game) ? -1 : Games.Keys.Where(g => Games[g] == game).First(); + return !Games.ContainsValue(game) ? -1 : Games.Keys.First(g => Games[g] == game); } public static void RemovePlayerFromGame(GameClient gameClient) { - try - { - if (gameClient == null) - { - Logger.Error("RemovePlayerFromGame() gameClient is null!"); - return; - } + try + { + if (gameClient == null) + { + Logger.Error("RemovePlayerFromGame() gameClient is null!"); + return; + } - foreach (var player in gameClient.Game.Players.Keys) - { - if (player == gameClient) - player.SendMessage(new QuitGameMessage() - { - PlayerIndex = gameClient.Player.PlayerIndex, - }); - else - player.SendMessage(new PlayerIndexMessage(Opcodes.PlayerLeaveGameMessage) //PlayerLeaveGameMessage - { - PlayerIndex = gameClient.Player.PlayerIndex, - }); - } + foreach (var player in gameClient.Game.Players.Keys) + { + if (player == gameClient) + player.SendMessage(new QuitGameMessage() + { + PlayerIndex = gameClient.Player.PlayerIndex, + }); + else + player.SendMessage( + new PlayerIndexMessage(Opcodes.PlayerLeaveGameMessage) //PlayerLeaveGameMessage + { + PlayerIndex = gameClient.Player.PlayerIndex, + }); + } - if (gameClient.Game != null) - { - var gameId = gameClient.Game.GameId; - if (!Games.ContainsKey(gameId)) return; + if (gameClient.Game != null) + { + var gameId = gameClient.Game.GameId; + if (!Games.ContainsKey(gameId)) return; - var game = Games[gameId]; - if (!game.Players.ContainsKey(gameClient)) return; + var game = Games[gameId]; + if (!game.Players.ContainsKey(gameClient)) return; - Player p = null; - if (!game.Players.TryRemove(gameClient, out p)) - { - Logger.Error("Can't remove player ({0}) from game with id: {1}", gameClient.Player.Toon.Name, gameId); - return; - } + Player p = null; + if (!game.Players.TryRemove(gameClient, out p)) + { + Logger.Error("Can't remove player ({0}) from game with id: {1}", gameClient.Player.Toon.Name, + gameId); + return; + } - if (p != null) - { + if (p != null) + { - //TODO: Move this inside player OnLeave event - var toon = p.Toon; - toon.TimePlayed += (int)(DateTimeExtensions.ToUnixTime(DateTime.UtcNow) - toon.LoginTime); - toon.ExperienceNext = p.ExperienceNext; + //TODO: Move this inside player OnLeave event + var toon = p.Toon; + toon.TimePlayed += (int)(DateTime.UtcNow.ToUnixTime() - toon.LoginTime); + toon.ExperienceNext = p.ExperienceNext; - ClientSystem.GameServer.GSBackend.PlayerLeft(gameId); + ClientSystem.GameServer.GSBackend.PlayerLeft(gameId); - if (p.InGameClient != null) - { - var minions = p.Followers.Keys.ToList(); - foreach (var minion in minions) - p.DestroyFollowerById(minion); - p.World.Leave(p); - } + if (p.InGameClient != null) + { + var minions = p.Followers.Keys.ToList(); + foreach (var minion in minions) + p.DestroyFollowerById(minion); + p.World.Leave(p); + } - if (gameClient.BnetClient != null) - { - gameClient.BnetClient.Account.GameAccount.ScreenStatus = D3.PartyMessage.ScreenStatus.CreateBuilder().SetScreen(1).SetStatus(0).Build(); - gameClient.BnetClient.Account.GameAccount.NotifyUpdate(); - - } - else - { - try { ClientSystem.GameServer.GSBackend.UpdateClient(toon.GameAccount.PersistentID, toon.Level, 1); } catch { Logger.Warn("Exception on RemovePlayerFromGame()"); } - } - } - } - else - { - Logger.Error("RemovePlayerFromGame() gameClient.Game is null!"); - } - } - catch { } + if (gameClient.BnetClient != null) + { + gameClient.BnetClient.Account.GameAccount.ScreenStatus = D3.PartyMessage.ScreenStatus + .CreateBuilder().SetScreen(1).SetStatus(0).Build(); + gameClient.BnetClient.Account.GameAccount.NotifyUpdate(); + + } + else + { + try + { + ClientSystem.GameServer.GSBackend.UpdateClient(toon.GameAccount.PersistentID, + toon.Level, 1); + } + catch + { + Logger.Warn("Exception on RemovePlayerFromGame()"); + } + } + } + } + else + { + Logger.Error("RemovePlayerFromGame() gameClient.Game is null!"); + } + } + catch (Exception ex) + { + Logger.ErrorException(ex, nameof(RemovePlayerFromGame)); + } } } } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GameUpdateManager.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GameUpdateManager.cs index 082d777..6854f0b 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GameUpdateManager.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GameUpdateManager.cs @@ -6,11 +6,12 @@ using DiIiS_NA.Core.Logging; namespace DiIiS_NA.GameServer.GSSystem.GameSystem { - public static class GameUpdateManager - { - private static readonly Logger Logger = LogManager.CreateLogger("ThreadSystem"); + [Obsolete("This class is obsolete and will be removed in the future.")] + public class GameUpdateManager + { + private static readonly Logger Logger = LogManager.CreateLogger(); - private static List UpdateWorkers = new List(); + private static readonly List _updateWorkers = new(); static GameUpdateManager() { @@ -22,17 +23,17 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem for (int coreId = 0; coreId < CPUCount; coreId++) { var thread = new GameUpdateThread(); - thread.CPUAffinity = (1UL << coreId); - UpdateWorkers.Add(thread); - var loopThread = new Thread(thread.Run) { Name = "UpdateWorkerThread", IsBackground = true }; ; // create the game update thread. + //thread.CPUAffinity = (1UL << coreId); + _updateWorkers.Add(thread); + var loopThread = new Thread(thread.Run) { Name = "UpdateWorkerThread", IsBackground = true }; loopThread.Start(); } - Logger.Info("Запущено {0} потоков", CPUCount); + Logger.Info("Started {0} threads", CPUCount); } public static GameUpdateThread FindWorker() { - return UpdateWorkers.OrderBy(t => t.Games.Count).First(); + return _updateWorkers.OrderBy(t => t.Games.Count).First(); } } } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GameUpdateThread.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GameUpdateThread.cs index 53a1867..caecebc 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GameUpdateThread.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/GameUpdateThread.cs @@ -37,7 +37,7 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem public void Run() { - List InactiveGames = new List(); + List inactiveGames = new List(); int missedTicks = 0; Thread.BeginThreadAffinity(); @@ -51,15 +51,15 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem while (true) { - Stopwatch _tickWatch = new Stopwatch(); - _tickWatch.Restart(); + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Restart(); lock (_lock) { foreach (var game in Games) { if (!game.Working) - InactiveGames.Add(game); + inactiveGames.Add(game); else { if (!game.UpdateInProgress) @@ -67,11 +67,15 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem game.UpdateInProgress = true; Task.Run(() => { - try - { - game.Update(); - } - catch { } + try + { + game.Update(); + } + catch (Exception ex) + { + Logger.ErrorException(ex, "Error in Game.Update()"); + } + game.MissedTicks = 0; game.UpdateInProgress = false; }); @@ -79,25 +83,33 @@ namespace DiIiS_NA.GameServer.GSSystem.GameSystem else { game.MissedTicks += 6; + if (game.MissedTicks > 60) + { + Logger.Warn("Game.Update() is running too slow. GameId: {0}", game.GameId); + game.MissedTicks = 0; + } } } } - foreach (var game in InactiveGames) - Games.Remove(game); + foreach (var game in inactiveGames) + { + game.Working = false; + Games.Remove(game); + } - InactiveGames.Clear(); + inactiveGames.Clear(); } - _tickWatch.Stop(); + stopwatch.Stop(); - var compensation = (int)(100 - _tickWatch.ElapsedMilliseconds); // the compensation value we need to sleep in order to get consistent 100 ms Game.Update(). + var compensation = (int)(100 - stopwatch.ElapsedMilliseconds); // the compensation value we need to sleep in order to get consistent 100 ms Game.Update(). - if (_tickWatch.ElapsedMilliseconds > 100) + if (stopwatch.ElapsedMilliseconds > 100) { - Logger.Trace("Game.Update() took [{0}ms] more than Game.UpdateFrequency [{1}ms].", _tickWatch.ElapsedMilliseconds, 100); - compensation = (int)(100 - (_tickWatch.ElapsedMilliseconds % 100)); - missedTicks = 6 * (int)(_tickWatch.ElapsedMilliseconds / 100); + Logger.Trace("Game.Update() took [{0}ms] more than Game.UpdateFrequency [{1}ms].", stopwatch.ElapsedMilliseconds, 100); + compensation = (int)(100 - (stopwatch.ElapsedMilliseconds % 100)); + missedTicks = 6 * (int)(stopwatch.ElapsedMilliseconds / 100); Thread.Sleep(Math.Max(0, compensation)); // sleep until next Update(). } else diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/QuestManager.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/QuestManager.cs index ea1ac37..c77c272 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/QuestManager.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/GameSystem/QuestManager.cs @@ -21,6 +21,7 @@ using DiIiS_NA.GameServer.MessageSystem; using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Map; using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Quest; using DiIiS_NA.GameServer.MessageSystem.Message.Fields; +using Spectre.Console; using Monster = DiIiS_NA.GameServer.GSSystem.ActorSystem.Monster; namespace DiIiS_NA.D3_GameServer.GSSystem.GameSystem @@ -29,11 +30,6 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.GameSystem { private static readonly Logger Logger = new(nameof(QuestManager)); - /// - /// Accessor for quests - /// - /// snoId of the quest to retrieve - /// public readonly Dictionary Quests = new(); public readonly Dictionary SideQuests = new(); @@ -164,12 +160,30 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.GameSystem Bounties.AddRange(actToKillUniqueBounties[BountyData.ActT.A5].Take(4)); } + private readonly struct Rewards + { + public int Experience { get; } + public int Gold { get; } + + public Rewards(int experience, int gold) + { + Experience = experience; + Gold = gold; + } + + public Rewards(float experience, float gold) : this((int) Math.Floor(experience), (int) Math.Floor(gold)) {} + } + + private Rewards GetCurrentQuestRewards() => + new Rewards(Quests[Game.CurrentQuest].RewardXp, Quests[Game.CurrentQuest].RewardGold); /// /// Advances a quest by a step /// /// snoID of the quest to advance public void Advance() { + int oldQuest = Game.CurrentQuest; + int oldStep = Game.CurrentStep; Quests[Game.CurrentQuest].Steps[Game.CurrentStep].Completed = true; Game.CurrentStep = Quests[Game.CurrentQuest].Steps[Game.CurrentStep].NextStep; Game.QuestProgress.QuestTriggers.Clear(); @@ -185,6 +199,13 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.GameSystem if (Quests[Game.CurrentQuest].Steps[Game.CurrentStep].NextStep != -1) { + Logger.QuestInfo( + $"{Emoji.Known.RightArrow} Step Advance ".StyleAnsi("deeppink4") + + $"Game #{Game.GameId.StyleAnsi("underline")} " + + $"from quest {oldQuest}/" + + $"step {oldStep.StyleAnsi("deeppink4")}" + + $"to quest {Game.CurrentQuest}'s " + + $"step {Game.CurrentStep.StyleAnsi("deeppink4")}"); } else { @@ -192,23 +213,25 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.GameSystem if (!Game.Empty) { SaveQuestProgress(true); - Logger.Trace( - $"$[white]$(Advance)$[/]$ Game {Game.GameId} Advanced to quest $[underline white]${Game.CurrentQuest}$[/]$, completed $[underline white]${Quests[Game.CurrentQuest].Completed}$[/]$"); + Logger.QuestInfo( + $"{Emoji.Known.NextTrackButton} Quest Advance ".StyleAnsi("white") + + $"Game #{Game.GameId.StyleAnsi("underline")} " + + $"from quest {oldQuest.StyleAnsi("turquoise2")}/" + + $"step {oldStep.StyleAnsi("deeppink4")}" + + $"to quest {Game.CurrentQuest.StyleAnsi("turquoise2")}/" + + $"step {Game.CurrentStep.StyleAnsi("deeppink4")}"); Game.BroadcastPlayers((client, player) => { - if (Game.CurrentQuest == 312429) return; // open world quest + if (Game.IsCurrentOpenWorld) return; // open world quest - int xpReward = (int)(Quests[Game.CurrentQuest].RewardXp * - Game.XpModifier); - int goldReward = (int)(Quests[Game.CurrentQuest].RewardGold * - Game.GoldModifier); + var rewards = GetCurrentQuestRewards(); player.InGameClient.SendMessage(new QuestStepCompleteMessage() { QuestStepComplete = QuestStepComplete.CreateBuilder() .SetReward(QuestReward.CreateBuilder() - .SetGoldGranted(goldReward) - .SetXpGranted((ulong)xpReward) + .SetGoldGranted(rewards.Gold) + .SetXpGranted((ulong)rewards.Experience) .SetSnoQuest(Game.CurrentQuest) ) .SetIsQuestComplete(true) @@ -224,7 +247,7 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.GameSystem WorldID = player.World.DynamicID(player), }, - Amount = xpReward, + Amount = rewards.Experience, Type = GameServer.MessageSystem.Message.Definitions.Base .FloatingAmountMessage.FloatType.Experience, }); @@ -238,13 +261,13 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.GameSystem WorldID = player.World.DynamicID(player), }, - Amount = goldReward, + Amount = rewards.Gold, Type = GameServer.MessageSystem.Message.Definitions.Base .FloatingAmountMessage.FloatType.Gold, }); - player.UpdateExp(xpReward); - player.Inventory.AddGoldAmount(goldReward); - player.AddAchievementCounter(74987243307173, (uint)goldReward); + player.UpdateExp(rewards.Experience); + player.Inventory.AddGoldAmount(rewards.Gold); + player.AddAchievementCounter(74987243307173, (uint)rewards.Gold); player.CheckQuestCriteria(Game.CurrentQuest); }); } @@ -270,7 +293,7 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.GameSystem if (!Game.Empty) { RevealQuestProgress(); - if ((Game.CurrentActEnum != ActEnum.OpenWorld && GameServerConfig.Instance.AutoSaveQuests) || + if ((Game.CurrentActEnum != ActEnum.OpenWorld && GameModsConfig.Instance.Quest.AutoSave) || Quests[Game.CurrentQuest].Steps[Game.CurrentStep].Saveable) SaveQuestProgress(false); } @@ -337,7 +360,7 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.GameSystem { player.World.SpawnRandomEquip(player, player, LootManager.Epic, player.Attributes[GameAttributes.Level]); } - var toon = player.Toon.DBToon; + var toon = player.Toon.DbToon; toon.EventsCompleted++; Game.GameDbSession.SessionUpdate(toon); player.CheckQuestCriteria(Game.CurrentSideQuest); @@ -827,7 +850,7 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.GameSystem { var questHistory = new DBQuestHistory { - DBToon = player.Toon.DBToon, + DBToon = player.Toon.DbToon, QuestId = Game.CurrentQuest, QuestStep = Game.CurrentStep }; diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/GeneratorsSystem/WorldGenerator.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/GeneratorsSystem/WorldGenerator.cs index 3030f93..88f462b 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/GeneratorsSystem/WorldGenerator.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/GeneratorsSystem/WorldGenerator.cs @@ -2295,7 +2295,7 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem } } - if (gizmoLocations.Count > 0 && world.Game.MonsterLevel >= Program.MaxLevel && FastRandom.Instance.Next(100) < 30) + if (gizmoLocations.Count > 0 && world.Game.MonsterLevel >= Program.MAX_LEVEL && FastRandom.Instance.Next(100) < 30) { var handleChest = new SNOHandle(96993); //leg chest if (handleChest == null) continue; diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/Affix.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/Affix.cs index 23e4065..4c6dc4f 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/Affix.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/Affix.cs @@ -23,42 +23,25 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem foreach (var asset in MPQStorage.Data.Assets[SNOGroup.GameBalance].Values) { GameBalance data = asset.Data as GameBalance; - if (data != null && data.Type == BalanceType.AffixList) + if (data is not { Type: BalanceType.AffixList }) continue; + foreach (AffixTable affixDefinition in data.Affixes.Where(affixDefinition => affixDefinition.Hash == AffixGbid)) { - foreach (var affixDefinition in data.Affixes) - { - if (affixDefinition.Hash == AffixGbid) return affixDefinition; - } + return affixDefinition; } } return null; } } - public int Price - { - get - { - return (Definition == null ? 0 : Definition.Cost); - } - } + public int Price => (Definition == null ? 0 : Definition.Cost); - public int ItemLevel - { - get - { - return (Definition == null ? 0 : Definition.AffixLevel); - } - } + public int ItemLevel => (Definition == null ? 0 : Definition.AffixLevel); public float Score = 0f; public int Rating { - get - { - return (int)(Price * (1 + Score)); - } + get => (int)(Price * (1 + Score)); set { } } @@ -69,7 +52,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem public override String ToString() { - return String.Format("{0}", AffixGbid); + return AffixGbid.ToString(); } public static Affix Parse(String affixString) diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/AffixGenerator.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/AffixGenerator.cs index aa1eb2b..e9cdef9 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/AffixGenerator.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/AffixGenerator.cs @@ -115,30 +115,30 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem if (Item.IsAccessory(item.ItemType) && affixesCount <= 1) affixesCount = 2; - bool IsUnique = item.ItemDefinition.Name.Contains("Unique_"); + bool isUnique = item.ItemDefinition.Name.Contains("Unique_"); - if (IsUnique && !isCrafting) affixesCount = item.ItemDefinition.BonusAffixes + item.ItemDefinition.BonusMajorAffixes + item.ItemDefinition.BonusMinorAffixes; + if (isUnique && !isCrafting) affixesCount = item.ItemDefinition.BonusAffixes + item.ItemDefinition.BonusMajorAffixes + item.ItemDefinition.BonusMinorAffixes; if (item.ItemDefinition.Name.ToLower().Contains("p71_ethereal")) { affixesCount = 8; - IsUnique = true; + isUnique = true; } if (item.GBHandle.GBID == -4139386) affixesCount = 6; //referral ring - if (IsUnique) + if (isUnique) affixesCount += 3; - Class ItemPlayerClass = Class.None; - if (item.ItemType.Usable.HasFlag(ItemFlags.Barbarian)) ItemPlayerClass = Class.Barbarian; - if (item.ItemType.Usable.HasFlag(ItemFlags.Crusader)) ItemPlayerClass = Class.Crusader; - if (item.ItemType.Usable.HasFlag(ItemFlags.Necromancer)) ItemPlayerClass = Class.Necromancer; - if (item.ItemType.Usable.HasFlag(ItemFlags.DemonHunter)) ItemPlayerClass = Class.DemonHunter; - if (item.ItemType.Usable.HasFlag(ItemFlags.Wizard)) ItemPlayerClass = Class.Wizard; - if (item.ItemType.Usable.HasFlag(ItemFlags.WitchDoctor)) ItemPlayerClass = Class.Witchdoctor; - if (item.ItemType.Usable.HasFlag(ItemFlags.Monk)) ItemPlayerClass = Class.Monk; + Class itemPlayerClass = Class.None; + if (item.ItemType.Usable.HasFlag(ItemFlags.Barbarian)) itemPlayerClass = Class.Barbarian; + if (item.ItemType.Usable.HasFlag(ItemFlags.Crusader)) itemPlayerClass = Class.Crusader; + if (item.ItemType.Usable.HasFlag(ItemFlags.Necromancer)) itemPlayerClass = Class.Necromancer; + if (item.ItemType.Usable.HasFlag(ItemFlags.DemonHunter)) itemPlayerClass = Class.DemonHunter; + if (item.ItemType.Usable.HasFlag(ItemFlags.Wizard)) itemPlayerClass = Class.Wizard; + if (item.ItemType.Usable.HasFlag(ItemFlags.WitchDoctor)) itemPlayerClass = Class.Witchdoctor; + if (item.ItemType.Usable.HasFlag(ItemFlags.Monk)) itemPlayerClass = Class.Monk; List itemTypes = ItemGroup.HierarchyToHashList(item.ItemType); @@ -162,14 +162,14 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem IEnumerable filteredList = null; filteredList = AllAffix.Where(a => - (a.PlayerClass == ItemPlayerClass || a.PlayerClass == Class.None) &&//(a.PlayerClass == ItemPlayerClass || a.PlayerClass == Class.None) && + (a.PlayerClass == itemPlayerClass || a.PlayerClass == Class.None) &&//(a.PlayerClass == ItemPlayerClass || a.PlayerClass == Class.None) && itemTypes.ContainsAtLeastOne(a.ItemGroup) && (a.AffixLevelMax >= levelToFind) && (a.OverrideLevelReq <= item.ItemDefinition.RequiredLevel) //!a.Name.Contains("1xx_Inferior") ); - if (IsUnique) + if (isUnique) { var restrictedFamily = item.ItemDefinition.LegendaryAffixFamily.Where(af => af != -1).ToHashSet(); filteredList = filteredList @@ -298,7 +298,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem //Logger.Debug("Affix " + def.Hash + ", final score is" + affix.Score); item.AffixList.Add(affix); - if (affixesCount > 0 && !IsUnique && !item.ItemDefinition.Name.Contains("StaffOfCow")) + if (affixesCount > 0 && !isUnique && !item.ItemDefinition.Name.Contains("StaffOfCow")) { item.RareItemName = GenerateItemName(); } @@ -306,7 +306,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem n++; } - if (IsUnique) + if (isUnique) { for (int i = 0; i < 6; i++) { diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/Item.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/Item.cs index 7572dbd..f0ee67d 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/Item.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/Item.cs @@ -31,7 +31,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem get; private set; //needed in Future, set this to true if Item affixes or item attributes have changed. } - + public override ActorType ActorType => ActorType.Item; public Actor Owner { get; set; } // Only set when the _actor_ has the item in its inventory. /fasbat @@ -43,10 +43,10 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem public bool Unidentified { get => Attributes[GameAttributes.Unidentified]; - set - { + set + { Attributes[GameAttributes.Unidentified] = value; - if (DBInventory is {} dbInventory) dbInventory.Unidentified = value; + if (DBInventory is { } dbInventory) dbInventory.Unidentified = value; } } @@ -832,14 +832,88 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem public override void OnTargeted(Player player, TargetMessage message) { + player.Inventory.RefreshInventoryToClient(); var playerAcc = player.InGameClient.BnetClient.Account.GameAccount; switch (SNO) { - case ActorSno._tieredlootrunkey_0: + case ActorSno._tieredlootrunkey_0: //Greater Rift Key playerAcc.BigPortalKey++; Destroy(); break; + case ActorSno._crafting_assortedparts_05: //Reusable Parts + playerAcc.CraftItem1++; + Destroy(); + break; + + case ActorSno._crafting_magic_05: //Arcanes Dust + playerAcc.CraftItem2++; + Destroy(); + break; + + case ActorSno._crafting_rare_05: //Veiled Crystal + playerAcc.CraftItem3++; + Destroy(); + break; + + case ActorSno._crafting_looted_reagent_05: //Death's Breath + playerAcc.CraftItem4++; + Destroy(); + break; + + case ActorSno._crafting_legendary_05: //Forgotten Soul + playerAcc.CraftItem5++; + Destroy(); + break; + + case ActorSno._craftingreagent_legendary_set_borns_x1: //Khanduran Rune Bounty itens Act I. + playerAcc.HoradricA1Res++; + Destroy(); + break; + + case ActorSno._craftingreagent_legendary_set_cains_x1: //Caldeum Nightshade Bounty itens Act II. + playerAcc.HoradricA2Res++; + Destroy(); + break; + + case ActorSno._craftingreagent_legendary_set_demon_x1: //Arreat War Tapestry Bounty itens Act III. + playerAcc.HoradricA3Res++; + Destroy(); + break; + + case ActorSno._craftingreagent_legendary_set_hallowed_x1: //Corrupted Angel Flesh Bounty itens Act IV. + playerAcc.HoradricA4Res++; + Destroy(); + break; + + case ActorSno._craftingreagent_legendary_set_captaincrimsons_x1: //Westmarch Holy Water Bounty itens Act V. + playerAcc.HoradricA5Res++; + Destroy(); + break; + + case ActorSno._demonorgan_skeletonking_x1: //Leorik Regret. + playerAcc.LeorikKey++; + Destroy(); + break; + + case ActorSno._demonorgan_ghom_x1: //Vial of Putridness. + playerAcc.VialofPutridness++; + Destroy(); + break; + + case ActorSno._demonorgan_siegebreaker_x1: //Idol of Terror. + playerAcc.IdolofTerror++; + Destroy(); + break; + + case ActorSno._demonorgan_diablo_x1: //Heart of Fright. + playerAcc.HeartofFright++; + Destroy(); + break; + //case ActorSno._currency_platinum_flippy: //Platinum coin + // playerAcc.Platinum++; + // Destroy(); + // break; default: player.Inventory.PickUp(this); break; @@ -902,7 +976,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem player.InGameClient.SendMessage( new MessageSystem.Message.Definitions.Base.GenericBlobMessage(Opcodes.CurrencyDataFull) - { Data = Moneys.Build().ToByteArray() }); + { Data = Moneys.Build().ToByteArray() }); } public virtual void OnRequestUse(Player player, Item target, int actionId, WorldPlace worldPlace) @@ -1195,7 +1269,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem player.InGameClient.SendMessage( new MessageSystem.Message.Definitions.Base.GenericBlobMessage(Opcodes.CurrencyDataFull) - { Data = moneys.Build().ToByteArray() }); + { Data = moneys.Build().ToByteArray() }); player.Inventory.DestroyInventoryItem(this); return; @@ -1353,7 +1427,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem player.Attributes[GameAttributes.Buff_Icon_Count0, powerId] = activated ? 0 : 1; player.Attributes.BroadcastChangedIfRevealed(); player.Inventory.SendVisualInventory(player); - var dbToon = player.Toon.DBToon; + var dbToon = player.Toon.DbToon; dbToon.WingsActive = player.CurrentWingsPowerId; player.World.Game.GameDbSession.SessionUpdate(dbToon); return; diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/ItemGenerator.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/ItemGenerator.cs index 81fabf9..7894bee 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/ItemGenerator.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/ItemGenerator.cs @@ -18,6 +18,7 @@ using DiIiS_NA.GameServer.Core.Types.TagMap; using DiIiS_NA.GameServer.MessageSystem; using DiIiS_NA.LoginServer.Toons; using DiIiS_NA.Core.Helpers.Math; +using DiIiS_NA.D3_GameServer; using DiIiS_NA.GameServer.GSSystem.PlayerSystem; namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem @@ -1358,8 +1359,8 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem private static void RandomSetUnidentified(Item item) => item.Unidentified = FastRandom.Instance.Chance(item.Name.Contains("unique", StringComparison.InvariantCultureIgnoreCase) || item.ItemDefinition.Quality is ItemTable.ItemQuality.Legendary or ItemTable.ItemQuality.Special or ItemTable.ItemQuality.Set - ? GameServerConfig.Instance.ChanceHighQualityUnidentified - : GameServerConfig.Instance.ChanceNormalUnidentified); + ? GameModsConfig.Instance.Items.UnidentifiedDropChances.HighQuality + : GameModsConfig.Instance.Items.UnidentifiedDropChances.NormalQuality); // Allows cooking a custom item. public static Item Cook(Player player, string name) diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/LootManager.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/LootManager.cs index 30ddf39..5d85f2e 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/LootManager.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/ItemsSystem/LootManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using DiIiS_NA.D3_GameServer; namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem { @@ -613,16 +614,16 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem switch (MonsterQuality) { case 0: //Normal - return new List { 0.18f * GameServerConfig.Instance.RateChangeDrop }; + return new List { 0.18f * GameModsConfig.Instance.Rate.ChangeDrop }; case 1: //Champion - return new List { 1f, 1f, 1f, 1f, 0.75f * GameServerConfig.Instance.RateChangeDrop }; + return new List { 1f, 1f, 1f, 1f, 0.75f * GameModsConfig.Instance.Rate.ChangeDrop }; case 2: //Rare (Elite) case 4: //Unique return new List { 1f, 1f, 1f, 1f, 1f }; case 7: //Boss - return new List { 1f, 1f, 1f, 1f, 1f, 0.75f * GameServerConfig.Instance.RateChangeDrop, 0.4f * GameServerConfig.Instance.RateChangeDrop }; + return new List { 1f, 1f, 1f, 1f, 1f, 0.75f * GameModsConfig.Instance.Rate.ChangeDrop, 0.4f * GameModsConfig.Instance.Rate.ChangeDrop }; default: - return new List { 0.12f * GameServerConfig.Instance.RateChangeDrop }; + return new List { 0.12f * GameModsConfig.Instance.Rate.ChangeDrop }; } } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/MapSystem/Scene.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/MapSystem/Scene.cs index 5c5352f..8c23019 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/MapSystem/Scene.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/MapSystem/Scene.cs @@ -24,6 +24,7 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; +using DiIiS_NA.D3_GameServer; using Actor = DiIiS_NA.GameServer.GSSystem.ActorSystem.Actor; namespace DiIiS_NA.GameServer.GSSystem.MapSystem @@ -549,7 +550,7 @@ namespace DiIiS_NA.GameServer.GSSystem.MapSystem SceneSNO = SceneSNO.Id, Transform = Transform, WorldID = World.GlobalID, - MiniMapVisibility = GameServerConfig.Instance.ForceMinimapVisibility + MiniMapVisibility = GameModsConfig.Instance.Minimap.ForceVisibility }; } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/MapSystem/World.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/MapSystem/World.cs index 168bbc8..e4e1021 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/MapSystem/World.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/MapSystem/World.cs @@ -10,6 +10,7 @@ using DiIiS_NA.Core.Helpers.Math; using DiIiS_NA.Core.Logging; using DiIiS_NA.Core.MPQ; using DiIiS_NA.Core.MPQ.FileFormats; +using DiIiS_NA.D3_GameServer; using DiIiS_NA.D3_GameServer.Core.Types.SNO; using DiIiS_NA.GameServer.Core.Types.Math; using DiIiS_NA.GameServer.Core.Types.QuadTrees; @@ -867,7 +868,7 @@ namespace DiIiS_NA.GameServer.GSSystem.MapSystem player.GroundItems[item.GlobalID] = item; DropItem(source, null, item); - if (source.Attributes[GameAttributes.Level] >= Program.MaxLevel) + if (source.Attributes[GameAttributes.Level] >= Program.MAX_LEVEL) { item = ItemGenerator.GenerateRandomCraftItem(player, 35); if (item == null) return; @@ -930,7 +931,7 @@ namespace DiIiS_NA.GameServer.GSSystem.MapSystem /// The position for drop. public void SpawnGold(Actor source, Player player, int Min = -1) { - int amount = (int)(LootManager.GetGoldAmount(player.Attributes[GameAttributes.Level]) * Game.GoldModifier * GameServerConfig.Instance.RateMoney); + int amount = (int)(LootManager.GetGoldAmount(player.Attributes[GameAttributes.Level]) * Game.GoldModifier * GameModsConfig.Instance.Rate.Gold); if (Min != -1) amount += Min; var item = ItemGenerator.CreateGold(player, amount); // somehow the actual ammount is not shown on ground /raist. diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/ConversationManager.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/ConversationManager.cs index 1ed0371..af53a94 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/ConversationManager.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/ConversationManager.cs @@ -65,7 +65,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem // If there is no matching childnode, there must be one with -1 which only combines all class specific into one private int GetDuration() { - var node = currentLineNode.ChildNodes.FirstOrDefault(a => a.ClassFilter == player.Toon.VoiceClassID); + var node = currentLineNode.ChildNodes.FirstOrDefault(a => a.ClassFilter == player.Toon.VoiceClassId); node ??= currentLineNode.ChildNodes.FirstOrDefault(a => a.ClassFilter == -1); if (node == null) @@ -74,7 +74,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem } return node.CompressedDisplayTimes[(int)manager.ClientLanguage] - .Languages[player.Toon.VoiceClassID * 2 + (player.Toon.Gender == 0 ? 0 : 1)]; + .Languages[player.Toon.VoiceClassId * 2 + (player.Toon.Gender == 0 ? 0 : 1)]; } // This returns the dynamicID of other conversation partners. The client uses its position to identify where you can hear the conversation. @@ -573,10 +573,10 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem LineID = currentLineNode.LineID, Speaker = currentLineNode.LineSpeaker, LineGender = -1, - AudioClass = (GameBalance.Class)player.Toon.VoiceClassID, + AudioClass = (GameBalance.Class)player.Toon.VoiceClassId, Gender = (player.Toon.Gender == 0) ? VoiceGender.Male : VoiceGender.Female, TextClass = currentLineNode.LineSpeaker == Speaker.Player - ? (GameBalance.Class)player.Toon.VoiceClassID + ? (GameBalance.Class)player.Toon.VoiceClassId : GameBalance.Class.None, SNOSpeakerActor = (int)GetSpeaker(currentLineNode.LineSpeaker).SNO, LineFlags = 0x00000000, diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/Inventory.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/Inventory.cs index 48f166a..13a742a 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/Inventory.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/Inventory.cs @@ -582,7 +582,8 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem ChangeItemLocationDB(old_x, old_y + 1, addedItem); destGrid.PlaceItem(addedItem, old_y + 1, old_x); } - }; + } + ; } else { @@ -1043,7 +1044,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem item.Owner = _owner; InventoryGrid targetGrid = (msg.InvLoc.EquipmentSlot == (int)EquipmentSlotId.Stash) ? _stashGrid : _inventoryGrid; - SaveItemToDB(_owner.Toon.GameAccount.DBGameAccount, _owner.Toon.DBToon, EquipmentSlotId.Inventory, item); + SaveItemToDB(_owner.Toon.GameAccount.DBGameAccount, _owner.Toon.DbToon, EquipmentSlotId.Inventory, item); ChangeItemLocationDB(msg.InvLoc.Column, msg.InvLoc.Row, item); item.UpdateStackCount(amount); targetGrid.PlaceItem(item, msg.InvLoc.Row, msg.InvLoc.Column); @@ -1198,12 +1199,12 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem (a.OverrideLevelReq <= Item.ItemDefinition.RequiredLevel) ); - if (!ReloadAffix.Definition.Name.Contains("Secondary")) filteredList = filteredList.Where( a => !a.Name.Contains("Secondary") ); + if (!ReloadAffix.Definition.Name.Contains("Secondary")) filteredList = filteredList.Where(a => !a.Name.Contains("Secondary")); if (!ReloadAffix.Definition.Name.Contains("Experience")) filteredList = filteredList.Where(a => !a.Name.Contains("Experience")); if (!ReloadAffix.Definition.Name.Contains("Archon")) filteredList = filteredList.Where(a => !a.Name.Contains("Archon")); // FIXME: always true? if (ReloadAffix.Definition.Hash == ReloadAffix.Definition.Hash) filteredList = filteredList.Where(a => a.Hash != ReloadAffix.Definition.Hash); - if (Item.GBHandle.GBID == -4139386) filteredList = filteredList.Where( a => !a.Name.Contains("Str") && !a.Name.Contains("Dex") && !a.Name.Contains("Int") && !a.Name.Contains("Vit" )); + if (Item.GBHandle.GBID == -4139386) filteredList = filteredList.Where(a => !a.Name.Contains("Str") && !a.Name.Contains("Dex") && !a.Name.Contains("Int") && !a.Name.Contains("Vit")); Dictionary bestDefinitions = new Dictionary(); @@ -1260,7 +1261,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem if (ReloadAffix.Definition.Name.Contains("Bracer")) result = (float)FastRandom.Instance.Next(1, 3); } - + if (GameAttributes.Attributes[effect.AttributeId] is GameAttributeF) { var attr = GameAttributes.Attributes[effect.AttributeId] as GameAttributeF; @@ -1286,7 +1287,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem foreach (var def in selectedGroups) { - if (def != null) + if (def != null) { List Scores = new List(); foreach (var effect in def.AttributeSpecifier) @@ -1300,7 +1301,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem if (Item.RandomGenerator == null) Item.RandomGenerator = new ItemRandomHelper(Item.Attributes[GameAttributes.Seed]); - + if (FormulaScript.Evaluate(effect.Formula.ToArray(), Item.RandomGenerator, out result, out minValue, out maxValue)) { if (effect.AttributeId == 369) continue; //Durability_Max @@ -1364,13 +1365,13 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem Field1 = (Item.Unidentified ? 0x00000002 : 0x00000001), aAffixGBIDs = affixGbis, }); - + //*/ } } #endregion _owner.GrantCriteria(74987255495718); - + } private void OnTrySalvageAllMessage(TrySalvageAllMessage msg) { @@ -1379,7 +1380,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem int count_reward = 0; switch (msg.SalvageType) { - + // Simple items case 0: foreach (var item in GetBackPackItems()) @@ -1549,7 +1550,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem return; Logger.Warn("Identifying items not implemented yet"); } - + private void OnInventoryUseIdentifyItemMessage(InventoryUseIdentifyItemMessage msg) { var item = GetItemByDynId(_owner, msg.ItemID); @@ -1557,14 +1558,15 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem return; int idDuration = 60; - _owner.StartCasting(idDuration, new Action(() => { + _owner.StartCasting(idDuration, new Action(() => + { item.Identify(); })); } //* private void OnTrySalvageMessage(TrySalvageMessage msg) { - + var item = GetItemByDynId(_owner, msg.ActorID); if (item == null) return; @@ -1633,8 +1635,8 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem _inventoryGrid.RemoveItem(item); item.Unreveal(_owner); - - + + bool haveBrimstone = false; Item brimstone = null; if (item.Attributes[GameAttributes.Item_Quality_Level] > 8 || FastRandom.Instance.Next(1, 1000) == 1) @@ -1656,9 +1658,9 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem gbidOriginalItem = item.GBHandle.GBID, IQLOriginalItem = Math.Min(item.Attributes[GameAttributes.Item_Quality_Level], 9), MaterialsResults = haveBrimstone ? 2 : 1, - gbidNewItems = new int[] { reward.GBHandle.GBID, haveBrimstone ? brimstone.GBHandle.GBID : -1, -1, -1 }, + gbidNewItems = new int[] { reward.GBHandle.GBID, haveBrimstone ? brimstone.GBHandle.GBID : -1, -1, -1 }, MaterialsCounts = new int[] { count_reward, haveBrimstone ? 1 : 0, 0, 0 } - + }); UpdateCurrencies(); @@ -1707,13 +1709,13 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem if (GetGoldAmount() < recipeDefinition.Gold) return; bool haveEnoughIngredients = true; - foreach (var ingr in recipeDefinition.Ingredients) + foreach (var ingr in recipeDefinition.Ingredients) { if (ingr.ItemsGBID == -1 || ingr.ItemsGBID == 0) continue; switch (ingr.ItemsGBID) { case -363607620: // Common parts. - if(_owner.Toon.GameAccount.CraftItem1 < ingr.Count) + if (_owner.Toon.GameAccount.CraftItem1 < ingr.Count) haveEnoughIngredients = false; break; case -1585802162: // Wizard Dust. @@ -1754,7 +1756,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem _stashGrid.RemoveItem(item); item.Unreveal(item.Owner as Player); } - else if(item.Attributes[GameAttributes.ItemStackQuantityLo] > ingr.Count) + else if (item.Attributes[GameAttributes.ItemStackQuantityLo] > ingr.Count) { item.Attributes[GameAttributes.ItemStackQuantityLo] -= ingr.Count; item.Attributes.BroadcastChangedIfRevealed(); @@ -1773,13 +1775,13 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem switch (ingr.ItemsGBID) { case -363607620: // Common parts. - _owner.Toon.GameAccount.CraftItem1 -= ingr.Count; + _owner.Toon.GameAccount.CraftItem1 -= ingr.Count; break; case -1585802162: // Wizard Dust. - _owner.Toon.GameAccount.CraftItem2 -= ingr.Count; + _owner.Toon.GameAccount.CraftItem2 -= ingr.Count; break; case -605947593: // Blurred Crystal. - _owner.Toon.GameAccount.CraftItem3 -= ingr.Count; + _owner.Toon.GameAccount.CraftItem3 -= ingr.Count; break; } } @@ -1800,7 +1802,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem } //else if (!(recipeDefinition.Name.StartsWith("T12_") || recipeDefinition.Name.StartsWith("T11_"))) - reward.Attributes[GameAttributes.Item_Quality_Level] = Math.Min(recipe.ItemSpecifierData.AdditionalRandomAffixes + 2 , 9); + reward.Attributes[GameAttributes.Item_Quality_Level] = Math.Min(recipe.ItemSpecifierData.AdditionalRandomAffixes + 2, 9); if (reward.Attributes[GameAttributes.Item_Quality_Level] < 9) { AffixGenerator.Generate(reward, recipe.ItemSpecifierData.AdditionalRandomAffixes, true); @@ -1925,7 +1927,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem if (reward.Attributes[GameAttributes.ItemStackQuantityLo] > 0) _inventoryGrid.AddItem(reward); client.SendMessage(new CraftingResultsMessage { annItem = reward.GlobalID, GBIDItem = recipe.ItemSpecifierData.ItemGBId, IQL = reward.Attributes[GameAttributes.Item_Quality_Level] }); - + UpdateCurrencies(); } @@ -2228,7 +2230,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem return _equipment.GetOffHand(); } - + public void AddGoldAmount(int amount, bool immediately = true) { @@ -2318,7 +2320,12 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem D3.Items.CurrencyData craft7Data = D3.Items.CurrencyData.CreateBuilder().SetId(20).SetCount(playerAcc.BigPortalKey).Build(); // KeyStone Greater Rift. - D3.Items.CurrencyData[] consumables = {goldData, bloodShardData, platinumData, craft1Data, craft2Data, craft3Data, craft4Data, craft5Data, craft7Data, horadric1Data, horadric2Data, horadric3Data, horadric4Data, horadric5Data, craft8Data, craft9Data, craft10Data, craft11Data}; + D3.Items.CurrencyData[] consumables = { + goldData, bloodShardData, platinumData, craft1Data, + craft2Data, craft3Data, craft4Data, craft5Data, craft7Data, + horadric1Data, horadric2Data, horadric3Data, horadric4Data, + horadric5Data, craft8Data, craft9Data, craft10Data, craft11Data + }; foreach (var consumable in consumables) { @@ -2404,7 +2411,8 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem _owner.SetAttributesByParagon(); CheckWeapons(); _owner.Attributes.BroadcastChangedIfRevealed(); - Task.Delay(3000).ContinueWith((t) => { + Task.Delay(3000).ContinueWith((t) => + { try { _owner.CheckBonusSets(); @@ -2421,7 +2429,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem _inventoryGold.Owner = _owner; _inventoryGold.SetInventoryLocation((int)EquipmentSlotId.Gold, 0, 0); _inventoryGold.Attributes.SendChangedMessage(_owner.InGameClient); - + //this.inventoryPotion = ItemGenerator.CreateItem(this._owner, ItemGenerator.GetItemDefinition(DiIiS_NA.Core.Helpers.Hash.StringHashHelper.HashItemName("HealthPotionBottomless"))); //this.inventoryPotion.Owner = _owner; //this.inventoryPotion.SetInventoryLocation((int)EquipmentSlotId.Inventory, 0, 0); @@ -2579,7 +2587,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem if (slotId == 15) item.DBInventory.DBToon = null; else - item.DBInventory.DBToon = (_owner as Player).Toon.DBToon; + item.DBInventory.DBToon = (_owner as Player).Toon.DbToon; item.Owner.World.Game.GameDbSession.SessionUpdate(item.DBInventory); //Logger.Debug("ChangeItemSlotDB success, item dbid: {0}", item.DBInventory.Id); diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/Player.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/Player.cs index 4fc04e6..66190d0 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/Player.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/Player.cs @@ -56,10 +56,12 @@ using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Pet; using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Game; using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Hireling; using DiIiS_NA.Core.Helpers.Hash; +using DiIiS_NA.D3_GameServer; using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Encounter; using DiIiS_NA.D3_GameServer.Core.Types.SNO; using DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Artisans; using DiIiS_NA.D3_GameServer.GSSystem.PlayerSystem; +using DiIiS_NA.LoginServer; using NHibernate.Util; namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem; @@ -106,7 +108,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable public List NecromancerSkeletons = new() { }; public bool ActiveSkeletons = false; - + public Actor ActiveGolem = null; public bool EnableGolem = false; @@ -221,9 +223,9 @@ public class Player : Actor, IMessageConsumer, IUpdateable if (value == null) { HirelingId = null; - lock (Toon.DBToon) + lock (Toon.DbToon) { - var dbToon = Toon.DBToon; + var dbToon = Toon.DbToon; dbToon.ActiveHireling = null; DBSessions.SessionUpdate(dbToon); } @@ -231,9 +233,9 @@ public class Player : Actor, IMessageConsumer, IUpdateable else if (value != _activeHireling) { HirelingId = value.Attributes[GameAttributes.Hireling_Class]; - lock (Toon.DBToon) + lock (Toon.DbToon) { - var dbToon = Toon.DBToon; + var dbToon = Toon.DbToon; dbToon.ActiveHireling = value.Attributes[GameAttributes.Hireling_Class]; DBSessions.SessionUpdate(dbToon); } @@ -292,10 +294,10 @@ public class Player : Actor, IMessageConsumer, IUpdateable PlayerGroupIndex = InGameClient.Game.PlayerGroupIndexCounter; Toon = bnetToon; LevelingBoosted = Toon.LevelingBoosted; - var dbToon = Toon.DBToon; + var dbToon = Toon.DbToon; HirelingId = dbToon.ActiveHireling; GBHandle.Type = (int)ActorType.Player; - GBHandle.GBID = Toon.ClassID; + GBHandle.GBID = Toon.ClassId; Level = dbToon.Level; ParagonLevel = Toon.ParagonLevel; ExperienceNext = Toon.ExperienceNext; @@ -355,7 +357,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable else if (InGameClient.Game.CurrentAct == 3000) EnableStoneOfRecall(); - var lores = UnserializeBytes(Toon.DBToon.Lore); + var lores = UnserializeBytes(Toon.DbToon.Lore); var num = 0; foreach (var lore in lores) { @@ -1446,10 +1448,10 @@ public class Player : Actor, IMessageConsumer, IUpdateable Attributes[GameAttributes.Casting_Speed] = 1f; //Basic stats - Attributes[GameAttributes.Level_Cap] = Program.MaxLevel; + Attributes[GameAttributes.Level_Cap] = Program.MAX_LEVEL; Attributes[GameAttributes.Level] = Level; Attributes[GameAttributes.Alt_Level] = ParagonLevel; - if (Level == Program.MaxLevel) + if (Level == Program.MAX_LEVEL) { Attributes[GameAttributes.Alt_Experience_Next_Lo] = (int)(ExperienceNext % uint.MaxValue); Attributes[GameAttributes.Alt_Experience_Next_Hi] = (int)(ExperienceNext / uint.MaxValue); @@ -2146,7 +2148,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable break; - #endregion + #endregion } } @@ -2194,7 +2196,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable // message.Amount have the value send to add on attr of Paragon tabs. ParagonBonuses[bonus.Category * 4 + bonus.Index - 1] += (ushort)message.Amount; - var dbToon = Toon.DBToon; + var dbToon = Toon.DbToon; dbToon.ParagonBonuses = ParagonBonuses; World.Game.GameDbSession.SessionUpdate(dbToon); @@ -2212,7 +2214,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable { ParagonBonuses = new ushort[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - var dbToon = Toon.DBToon; + var dbToon = Toon.DbToon; dbToon.ParagonBonuses = ParagonBonuses; World.Game.GameDbSession.SessionUpdate(dbToon); @@ -2480,6 +2482,21 @@ public class Player : Actor, IMessageConsumer, IUpdateable public bool SpeedCheckDisabled = false; + public float StrengthMultiplier => ParagonLevel > 0 + ? GameModsConfig.Instance.Player.Multipliers.Strength.Paragon + : GameModsConfig.Instance.Player.Multipliers.Strength.Normal; + public float DexterityMultiplier => ParagonLevel > 0 + ? GameModsConfig.Instance.Player.Multipliers.Dexterity.Paragon + : GameModsConfig.Instance.Player.Multipliers.Dexterity.Normal; + + public float IntelligenceMultiplier => ParagonLevel > 0 + ? GameModsConfig.Instance.Player.Multipliers.Intelligence.Paragon + : GameModsConfig.Instance.Player.Multipliers.Intelligence.Normal; + + public float VitalityMultiplier => ParagonLevel > 0 + ? GameModsConfig.Instance.Player.Multipliers.Vitality.Paragon + : GameModsConfig.Instance.Player.Multipliers.Intelligence.Normal; + public static byte[] StringToByteArray(string hex) { return Enumerable.Range(0, hex.Length) @@ -2628,7 +2645,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable Logger.WarnException(ex, "OnLoadWorldActions"); } } - + World.Game.OnLoadWorldActions[World.SNO].Clear(); } } @@ -2636,7 +2653,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable if (World.Game.OnLoadSceneActions.ContainsKey(CurrentScene.SceneSNO.Id)) { Logger.MethodTrace($"OnLoadSceneActions: {CurrentScene.SceneSNO.Id}"); - + Logger.MethodTrace(World.SNO.ToString()); lock (World.Game.OnLoadSceneActions[CurrentScene.SceneSNO.Id]) { @@ -2674,8 +2691,9 @@ public class Player : Actor, IMessageConsumer, IUpdateable Logger.WarnException(e, "questEvent()"); } } - // Reset resurrection charges on zone change - TODO: do not reset charges on reentering the same zone - Attributes[GameAttributes.Corpse_Resurrection_Charges] = GameServerConfig.Instance.ResurrectionCharges; + // Reset resurrection charges on zone change + // TODO: do not reset charges on reentering the same zone + Attributes[GameAttributes.Corpse_Resurrection_Charges] = GameModsConfig.Instance.Health.ResurrectionCharges; #if DEBUG Logger.Warn($"Player Location {Toon.Name}, Scene: {CurrentScene.SceneSNO.Name} SNO: {CurrentScene.SceneSNO.Id} LevelArea: {CurrentScene.Specification.SNOLevelAreas[0]}"); @@ -2884,7 +2902,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable //*/ private void OnEquipPotion(GameClient client, ChangeUsableItemMessage message) { - var activeSkills = Toon.DBActiveSkills; + var activeSkills = Toon.DbActiveSkills; activeSkills.PotionGBID = message.Field1; World.Game.GameDbSession.SessionUpdate(activeSkills); } @@ -2990,9 +3008,9 @@ public class Player : Actor, IMessageConsumer, IUpdateable private bool DisconnectIdle() { - if (!GameServerConfig.Instance.AfkDisconnect || InGameClient.Game.TickCounter - LastMovementTick <= 54000) + if (!GameServerConfig.Instance.AfkDisconnect || InGameClient.Game.TickCounter - LastMovementTick <= 54000) return false; - + Logger.Warn($"Player $[underline white]${Name}$[/]$ disconnected for being AFK."); Opcodes.CloseGameMessage.SendTo(InGameClient); return true; @@ -3002,7 +3020,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable { if (BetweenWorlds) return; if (DisconnectIdle()) return; - + // Check the gold if (InGameClient.Game.TickCounter % 120 == 0 && World != null && GoldCollectedTempCount > 0) { @@ -3197,7 +3215,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable }); World.Leave(skeleton); } - catch{} + catch { } } NecromancerSkeletons.Clear(); @@ -3604,8 +3622,13 @@ public class Player : Actor, IMessageConsumer, IUpdateable System.Threading.Tasks.Task.Delay(3).Wait(); RevealActorsToPlayer(); + if (!_motdSent && LoginServer.LoginServerConfig.Instance.MotdEnabled) + { + if (!LoginServerConfig.Instance.MotdEnabledWhenWorldLoads) + _motdSent = true; InGameClient.BnetClient.SendMotd(); + } // } @@ -3989,10 +4012,10 @@ public class Player : Actor, IMessageConsumer, IUpdateable get { var baseStrength = 0.0f; - var multiplier = ParagonLevel > 0 ? GameServerConfig.Instance.StrengthParagonMultiplier : GameServerConfig.Instance.StrengthMultiplier; + var multiplier = StrengthMultiplier; baseStrength = Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Strength - ? Toon.HeroTable.Strength + (Level - 1) * 3 - : Toon.HeroTable.Strength + (Level - 1); + ? Toon.HeroTable.Strength + (Level - 1) * 3 + : Toon.HeroTable.Strength + (Level - 1); return baseStrength * multiplier; } @@ -4005,8 +4028,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable { get { - var multiplier = ParagonLevel > 0 ? GameServerConfig.Instance.DexterityParagonMultiplier : GameServerConfig.Instance.DexterityMultiplier; - + var multiplier = DexterityMultiplier; return Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Dexterity ? Toon.HeroTable.Dexterity + (Level - 1) * 3 * multiplier : Toon.HeroTable.Dexterity + (Level - 1) * multiplier; @@ -4016,7 +4038,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable public float TotalDexterity => Attributes[GameAttributes.Dexterity] + Inventory.GetItemBonus(GameAttributes.Dexterity_Item); - public float Vitality => Toon.HeroTable.Vitality + (Level - 1) * 2 * (ParagonLevel > 0 ? GameServerConfig.Instance.VitalityParagonMultiplier : GameServerConfig.Instance.VitalityMultiplier); + public float Vitality => Toon.HeroTable.Vitality + (Level - 1) * 2 * (VitalityMultiplier); public float TotalVitality => Attributes[GameAttributes.Vitality] + Inventory.GetItemBonus(GameAttributes.Vitality_Item); @@ -4025,7 +4047,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable { get { - var multiplier = ParagonLevel > 0 ? GameServerConfig.Instance.IntelligenceParagonMultiplier : GameServerConfig.Instance.IntelligenceMultiplier; + var multiplier = IntelligenceMultiplier; return Toon.HeroTable.CoreAttribute == GameBalance.PrimaryAttribute.Intelligence ? Toon.HeroTable.Intelligence + (Level - 1) * 3 * multiplier : Toon.HeroTable.Intelligence + (Level - 1) * multiplier; @@ -4076,7 +4098,9 @@ public class Player : Actor, IMessageConsumer, IUpdateable HotBarButtons = SkillSet.HotBarSkills, HotBarButton = new HotbarButtonData { - SNOSkill = -1, RuneType = -1, ItemGBId = + SNOSkill = -1, + RuneType = -1, + ItemGBId = StringHashHelper.HashItemName( "HealthPotionBottomless") //2142362846//this.Toon.DBActiveSkills.PotionGBID , @@ -4084,7 +4108,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable }, SkillSlotEverAssigned = 0x0F, //0xB4, PlaytimeTotal = Toon.TimePlayed, - WaypointFlags = GameServerConfig.Instance.UnlockAllWaypoints ? 0x0000ffff : World.Game.WaypointFlags, + WaypointFlags = GameModsConfig.Instance.Quest.UnlockAllWaypoints ? 0x0000ffff : World.Game.WaypointFlags, HirelingData = new HirelingSavedData() { HirelingInfos = HirelingInfo, @@ -4203,7 +4227,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable serialized += Inventory.GetItemBonus(GameAttributes.Armor_Item).ToString("F0"); serialized += ";"; serialized += totalDamage.ToString("F0"); - var dbStats = Toon.DBToon; + var dbStats = Toon.DbToon; dbStats.Stats = serialized; World.Game.GameDbSession.SessionUpdate(dbStats); } @@ -4300,7 +4324,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable else { bonusSet.Claimed = true; - bonusSet.ClaimedToon = Toon.DBToon; + bonusSet.ClaimedToon = Toon.DbToon; } //BonusSetsList.CollectionEditions[bonusSet.SetId].Claim(this); @@ -4318,8 +4342,14 @@ public class Player : Actor, IMessageConsumer, IUpdateable //returns empty data var emptyHireling = new HirelingInfo { - HirelingIndex = type, GbidName = 0x0000, Dead = false, Skill1SNOId = -1, Skill2SNOId = -1, - Skill3SNOId = -1, Skill4SNOId = -1, annItems = -1 + HirelingIndex = type, + GbidName = 0x0000, + Dead = false, + Skill1SNOId = -1, + Skill2SNOId = -1, + Skill3SNOId = -1, + Skill4SNOId = -1, + annItems = -1 }; return emptyHireling; } @@ -4370,7 +4400,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable public void LearnRecipe(ArtisanType? artisan, int recipe) { Logger.Trace("Learning recipe #{0}, Artisan type: {1}", recipe, artisan); - + /*var query = this.World.Game.GameDBSession.SessionQuerySingle( dbi => dbi.DBGameAccount.Id == this.Toon.GameAccount.PersistentID && @@ -4477,18 +4507,18 @@ public class Player : Actor, IMessageConsumer, IUpdateable if (BlacksmithUnlocked || InGameClient.Game.CurrentAct == 3000) InGameClient.SendMessage(new GenericBlobMessage(Opcodes.CraftingDataBlacksmithInitialMessage) - { Data = blacksmith.ToByteArray() }); + { Data = blacksmith.ToByteArray() }); if (JewelerUnlocked || InGameClient.Game.CurrentAct == 3000) InGameClient.SendMessage(new GenericBlobMessage(Opcodes.CraftingDataJewelerInitialMessage) - { Data = jeweler.ToByteArray() }); + { Data = jeweler.ToByteArray() }); if (MysticUnlocked || InGameClient.Game.CurrentAct == 3000) { InGameClient.SendMessage(new GenericBlobMessage(Opcodes.CraftingDataMysticInitialMessage) - { Data = mystic.ToByteArray() }); + { Data = mystic.ToByteArray() }); InGameClient.SendMessage(new GenericBlobMessage(Opcodes.CraftingDataTransmogInitialMessage) - { Data = transmog.ToByteArray() }); + { Data = transmog.ToByteArray() }); } } @@ -4507,8 +4537,8 @@ public class Player : Actor, IMessageConsumer, IUpdateable foreach (var mail in mailData) { var mailRow = D3.Items.Mail.CreateBuilder() - .SetAccountTo(Toon.D3EntityID) - .SetAccountFrom(Toon.D3EntityID) + .SetAccountTo(Toon.D3EntityId) + .SetAccountFrom(Toon.D3EntityId) .SetMailId(mail.Id) .SetTitle(mail.Title) .SetBody(mail.Body); @@ -4587,7 +4617,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable private readonly Dictionary _achievementCounters = new(); public int DodgesInARow { get; set; } = 0; - public int BlocksInARow { get; set; }= 0; + public int BlocksInARow { get; set; } = 0; public void GrantAchievement(ulong id) { @@ -5092,13 +5122,15 @@ public class Player : Actor, IMessageConsumer, IUpdateable if (World.Game.IsHardcore && Attributes[GameAttributes.Level] >= 70) addedExp *= 5; - if (Attributes[GameAttributes.Alt_Level] >= 515) - { - var XPcap = 91.262575239831f * Math.Pow(Attributes[GameAttributes.Alt_Level], 3) - - 44301.083380565047f * Math.Pow(Attributes[GameAttributes.Alt_Level], 2) + - 3829010.395566940308f * Attributes[GameAttributes.Alt_Level] + 322795582.543823242188f; - addedExp = (int)((float)(ParagonLevelBorders[Attributes[GameAttributes.Alt_Level]] / XPcap) * addedExp); - } + // To'do verify this formula. + // Remove this if to remove paragon level cap. + //if (Attributes[GameAttributes.Alt_Level] >= 515) + //{ + // var XPcap = 91.262575239831f * Math.Pow(Attributes[GameAttributes.Alt_Level], 3) - + // 44301.083380565047f * Math.Pow(Attributes[GameAttributes.Alt_Level], 2) + + // 3829010.395566940308f * Attributes[GameAttributes.Alt_Level] + 322795582.543823242188f; + // addedExp = (int)((float)(ParagonLevelBorders[Attributes[GameAttributes.Alt_Level]] / XPcap) * addedExp); + //} if (Attributes[GameAttributes.Rest_Experience_Lo] > 0) { @@ -5493,7 +5525,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable { if (InGameClient.Game.ActiveNephalemTimer && InGameClient.Game.ActiveNephalemKilledMobs == false) { - InGameClient.Game.ActiveNephalemProgress += 15f * GameServerConfig.Instance.NephalemRiftProgressMultiplier; + InGameClient.Game.ActiveNephalemProgress += 15f * GameModsConfig.Instance.NephalemRift.ProgressMultiplier; foreach (var plr in InGameClient.Game.Players.Values) { plr.InGameClient.SendMessage(new FloatDataMessage(Opcodes.DunggeonFinderProgressGlyphPickUp) @@ -5563,9 +5595,9 @@ public class Player : Actor, IMessageConsumer, IUpdateable }); plr.InGameClient.SendMessage(new DisplayGameTextMessage(Opcodes.DisplayGameChatTextMessage) - { Message = "Messages:LR_BossSpawned" }); + { Message = "Messages:LR_BossSpawned" }); plr.InGameClient.SendMessage(new DisplayGameTextMessage(Opcodes.DisplayGameTextMessage) - { Message = "Messages:LR_BossSpawned" }); + { Message = "Messages:LR_BossSpawned" }); } StartConversation(World, 366542); @@ -5665,40 +5697,40 @@ public class Player : Actor, IMessageConsumer, IUpdateable case 0: return; case > 0: - { - if (Attributes[GameAttributes.Hitpoints_Cur] < Attributes[GameAttributes.Hitpoints_Max_Total]) { - if (Toon.Class == ToonClass.Barbarian) - if (SkillSet.HasPassive(205217)) - quantity += 0.01f * Attributes[GameAttributes.Health_Globe_Bonus_Health]; - - if (guidingLight) //Monk -> Guiding Light + if (Attributes[GameAttributes.Hitpoints_Cur] < Attributes[GameAttributes.Hitpoints_Max_Total]) { - var missingHP = - (Attributes[GameAttributes.Hitpoints_Max_Total] - Attributes[GameAttributes.Hitpoints_Cur]) / - Attributes[GameAttributes.Hitpoints_Max_Total]; - if (missingHP > 0.05f) - if (!World.BuffManager.HasBuff(this)) - World.BuffManager.AddBuff(this, this, - new GuidingLightBuff(Math.Min(missingHP, 0.3f), - TickTimer.WaitSeconds(World.Game, 10.0f))); + if (Toon.Class == ToonClass.Barbarian) + if (SkillSet.HasPassive(205217)) + quantity += 0.01f * Attributes[GameAttributes.Health_Globe_Bonus_Health]; + + if (guidingLight) //Monk -> Guiding Light + { + var missingHP = + (Attributes[GameAttributes.Hitpoints_Max_Total] - Attributes[GameAttributes.Hitpoints_Cur]) / + Attributes[GameAttributes.Hitpoints_Max_Total]; + if (missingHP > 0.05f) + if (!World.BuffManager.HasBuff(this)) + World.BuffManager.AddBuff(this, this, + new GuidingLightBuff(Math.Min(missingHP, 0.3f), + TickTimer.WaitSeconds(World.Game, 10.0f))); + } + + Attributes[GameAttributes.Hitpoints_Cur] = Math.Min( + Attributes[GameAttributes.Hitpoints_Cur] + quantity, + Attributes[GameAttributes.Hitpoints_Max_Total]); + + Attributes.BroadcastChangedIfRevealed(); + InGameClient.SendMessage(new FloatingNumberMessage + { + ActorID = DynamicID(this), + Number = quantity, + Type = FloatingNumberMessage.FloatType.Green + }); } - Attributes[GameAttributes.Hitpoints_Cur] = Math.Min( - Attributes[GameAttributes.Hitpoints_Cur] + quantity, - Attributes[GameAttributes.Hitpoints_Max_Total]); - - Attributes.BroadcastChangedIfRevealed(); - InGameClient.SendMessage(new FloatingNumberMessage - { - ActorID = DynamicID(this), - Number = quantity, - Type = FloatingNumberMessage.FloatType.Green - }); + break; } - - break; - } default: Attributes[GameAttributes.Hitpoints_Cur] = Math.Max( Attributes[GameAttributes.Hitpoints_Cur] + quantity, @@ -5961,7 +5993,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable LearnedLore.Count++; // Count UpdateHeroState(); Logger.Trace("Learning lore #{0}", loreSNOId); - var dbToon = Toon.DBToon; + var dbToon = Toon.DbToon; dbToon.Lore = SerializeBytes(LearnedLore.m_snoLoreLearned.Take(LearnedLore.Count).ToList()); World.Game.GameDbSession.SessionUpdate(dbToon); } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/General/DrinkHealthPotion.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/General/DrinkHealthPotion.cs index 28b7709..8877e1e 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/General/DrinkHealthPotion.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/General/DrinkHealthPotion.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using DiIiS_NA.D3_GameServer; using DiIiS_NA.GameServer.GSSystem.PlayerSystem; using DiIiS_NA.GameServer.GSSystem.TickerSystem; using DiIiS_NA.LoginServer; @@ -12,8 +13,8 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations.General public override IEnumerable Run() { if (User is not Player player) yield break; - player.AddPercentageHP(GameServerConfig.Instance.HealthPotionRestorePercentage); - AddBuff(player, player, new CooldownBuff(30211, TickTimer.WaitSeconds(player.World.Game, GameServerConfig.Instance.HealthPotionCooldown))); + player.AddPercentageHP(GameModsConfig.Instance.Health.PotionRestorePercentage); + AddBuff(player, player, new CooldownBuff(30211, TickTimer.WaitSeconds(player.World.Game, GameModsConfig.Instance.Health.PotionCooldown))); } } } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/HeroSkills/Crusader.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/HeroSkills/Crusader.cs index 5de07be..6f00fd8 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/HeroSkills/Crusader.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/HeroSkills/Crusader.cs @@ -148,7 +148,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations if (Rune_B > 0) DmgType = DamageType.Lightning; //Electrify AttackPayload attack = new AttackPayload(this); attack.Targets = GetEnemiesInArcDirection(User.Position, TargetPosition, 12f, Rune_D > 0 ? 120f : 90f); //Carve - if (Rune_C > 0) attack.chcBonus = ScriptFormula(14); //Crush + if (Rune_C > 0) attack.ChcBonus = ScriptFormula(14); //Crush attack.AddWeaponDamage(ScriptFormula(0), DmgType); attack.OnHit = hitPayload => { @@ -3150,7 +3150,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations attack.Targets = GetEnemiesInRadius(point, 12f); attack.AddWeaponDamage(ScriptFormula(3), DamageType.Physical); if (Rune_B > 0) //Annihilate - attack.chcBonus = 1f; //will be capped to 85% anyway + attack.ChcBonus = 1f; //will be capped to 85% anyway attack.OnHit = (hitPayload) => { if (Rune_A > 0) //Barrels of tar diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/HeroSkills/Necromancer.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/HeroSkills/Necromancer.cs index 7628543..94630fa 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/HeroSkills/Necromancer.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Implementations/HeroSkills/Necromancer.cs @@ -1264,7 +1264,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations } } #endregion - //Done + //Done - testing, apparently Rune_A not working. #region CorpseExlosion [ImplementsPowerSNO(SkillsSystem.Skills.Necromancer.ExtraSkills.CorpseExlosion)] @@ -1272,72 +1272,86 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations { public override IEnumerable Main() { - //ScriptFormulaDetails_Fields - //PowerDefinition_Fields - //Мертвячинка) - if (player.SkillSet.HasPassive(208594)) 454066 - if (Rune_B > 0) - ((Player) User).AddPercentageHP(-2); - float Radius = 20f; - float Damage = 10.5f; - DamageType DType = DamageType.Physical; - var PowerData = (DiIiS_NA.Core.MPQ.FileFormats.Power)MPQStorage.Data.Assets[SNOGroup.Power][PowerSNO].Data; - var Point = SpawnEffect(ActorSno._p6_necro_bonespikes, TargetPosition, 0, WaitSeconds(0.2f)); - Point.PlayEffect(Effect.PlayEffectGroup, RuneSelect(459954, 473926, 459954, 473907, 459954//D - , 473864)); + // Initializing main variables for Bonespikes ability. + float radius = 20f; + float damage = 10.5f; + DamageType damageType = DamageType.Physical; + + // Fetching the data for the respective Power from the MPQ cache. + var powerData = (DiIiS_NA.Core.MPQ.FileFormats.Power)MPQStorage.Data.Assets[SNOGroup.Power][PowerSNO].Data; + + // Creating a point effect on the target position, playing various effect groups depending on the selected Rune. + var point = SpawnEffect(ActorSno._p6_necro_bonespikes, TargetPosition, 0, WaitSeconds(0.2f)); + point.PlayEffect(Effect.PlayEffectGroup, RuneSelect(459954, 473926, 459954, 473907, 459954, 473864)); + + // Depending on a specific game attribute, either spawn a new monster at the target position, or select up to five existing corpses. var actors = User.Attributes[GameAttributes.Necromancer_Corpse_Free_Casting] ? new List { User.World.SpawnMonster(ActorSno._p6_necro_corpse_flesh, TargetPosition).GlobalID } - : User.GetActorsInRange(TargetPosition, 11).Where(x => x.SNO == ActorSno._p6_necro_corpse_flesh).Select(x => x.GlobalID).Take(5).ToList(); - if (Rune_D > 0) - Radius = 25f; - else if (Rune_C > 0)//licking action - { Damage = 15.75f; DType = DamageType.Poison; } - else if (Rune_A > 0) - DType = DamageType.Poison; + : User.GetActorsInRange(TargetPosition, 11).Where(x => x.SNO == ActorSno._p6_necro_corpse_flesh) + .Select(x => x.GlobalID).Take(5).ToList(); + // Modifying main parameters of the ability depending on the selected Rune. + if (Rune_D > 0) + { + radius = 25f; + } + else if (Rune_C > 0) // Licking action. + { + damage = 15.75f; + damageType = DamageType.Poison; + } + else if (Rune_A > 0) + { + damageType = DamageType.Poison; + } + + // Applying the effects of the Bonespikes ability on the selected corpses. foreach (var actor in actors) { - if (Rune_B > 0) { var bomb = World.GetActorByGlobalId(actor); var nearestEnemy = bomb.GetActorsInRange(20f).First(); if (nearestEnemy != null) bomb.Teleport(nearestEnemy.Position); - } - - var Explosion = SpawnEffect( + + // Spawning explosion effect. + var explosionEffect = SpawnEffect( ActorSno._p6_necro_corpseexplosion_projectile_spawn, World.GetActorByGlobalId(actor).Position, ActorSystem.Movement.MovementHelpers.GetFacingAngle(User, World.GetActorByGlobalId(actor)), WaitSeconds(0.2f) ); - Explosion.PlayEffect(Effect.PlayEffectGroup, RuneSelect(457183, 471539, 471258, 471249, 471247, 471236)); + explosionEffect.PlayEffect(Effect.PlayEffectGroup, + RuneSelect(457183, 471539, 471258, 471249, 471247, 471236)); + explosionEffect.UpdateDelay = 0.1f; - Explosion.UpdateDelay = 0.1f; - Explosion.OnUpdate = () => + explosionEffect.OnUpdate = () => { - AttackPayload attack = new AttackPayload(this) + // Creating the attack payload. + AttackPayload attack = new(this) { - Targets = GetEnemiesInRadius(User.Position, Radius) + Targets = GetEnemiesInRadius(User.Position, radius) }; if (Rune_E > 0) - DType = DamageType.Cold; - - attack.AddWeaponDamage(Damage, DType); + damageType = DamageType.Cold; + + // Applying weapon damage. + attack.AddWeaponDamage(damage, damageType); attack.OnHit = hitPayload => { if (Rune_E > 0) AddBuff(hitPayload.Target, new DebuffFrozen(WaitSeconds(2f))); }; + // Applying the attack. attack.Apply(); }; + // Destroying the selected corpse. World.GetActorByGlobalId(actor).Destroy(); } - - //}); yield break; } } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Payloads/AttackPayload.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Payloads/AttackPayload.cs index d4a1ced..12dc3a5 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Payloads/AttackPayload.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Payloads/AttackPayload.cs @@ -16,7 +16,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads // list of targets to try and hit with this payload, must be set before calling Apply() public TargetList Targets; - public float chcBonus = 0f; + public float ChcBonus = 0f; // list of each amount and type of damage the attack will contain public class DamageEntry @@ -115,7 +115,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads if (target == null || target.World == null || target.World != null && target.World.PowerManager.IsDeletingActor(target)) continue; - var payload = new HitPayload(this, _DoCriticalHit(Context.User, target, chcBonus) + var payload = new HitPayload(this, _DoCriticalHit(Context.User, target, ChcBonus) , target); payload.AutomaticHitEffects = AutomaticHitEffects; payload.OnDeath = OnDeath; diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Payloads/DeathPayload.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Payloads/DeathPayload.cs index 720170d..2b619d2 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Payloads/DeathPayload.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Payloads/DeathPayload.cs @@ -14,6 +14,7 @@ using DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations; using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Effect; using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Combat; using DiIiS_NA.Core.Helpers.Math; +using DiIiS_NA.D3_GameServer; using DiIiS_NA.LoginServer.Toons; using DiIiS_NA.GameServer.Core.Types.TagMap; using DiIiS_NA.GameServer.GSSystem.GeneratorsSystem; @@ -27,7 +28,7 @@ using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Quest; using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.World; using DiIiS_NA.GameServer.MessageSystem.Message.Fields; using DiIiS_NA.D3_GameServer.Core.Types.SNO; - +using static DiIiS_NA.Core.MPQ.FileFormats.Monster.MonsterType; namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads { public class DeathPayload : Payload @@ -123,7 +124,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads } if (Target is Minion { Master: Player masterPlr2 } - and (BaseGolem or IceGolem or BoneGolem or DecayGolem or ConsumeFleshGolem or BloodGolem)) + and (BaseGolem or IceGolem or BoneGolem or DecayGolem or ConsumeFleshGolem or DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Minions.BloodGolem)) { masterPlr2.InGameClient.SendMessage(new MessageSystem.Message.Definitions.Pet.PetDetachMessage() { @@ -425,7 +426,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads { grantedExp = (int)(grantedExp * rangedPlayer.World.Game.XpModifier); - float tempExp = grantedExp * GameServerConfig.Instance.RateExp; + float tempExp = grantedExp * GameModsConfig.Instance.Rate.Experience; rangedPlayer.UpdateExp(Math.Max((int)tempExp, 1)); var a = (int)rangedPlayer.Attributes[GameAttributes.Experience_Bonus]; @@ -444,7 +445,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads { if (rangedPlayer.Toon.Class == ToonClass.DemonHunter) { - if (monster.MonsterType == (int)DiIiS_NA.Core.MPQ.FileFormats.Monster.MonsterType.Demon) + if (monster.MonsterTypeValue == (int)DiIiS_NA.Core.MPQ.FileFormats.Monster.MonsterType.Demon) rangedPlayer.AddAchievementCounter(74987243307065, 1); if (PowerMath.Distance2D(rangedPlayer.Position, monster.Position) >= 45f) @@ -636,13 +637,13 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads Target.World.Game.ActiveNephalemTimer && Target.World.Game.ActiveNephalemKilledMobs == false) { Target.World.Game.ActiveNephalemProgress += - GameServerConfig.Instance.NephalemRiftProgressMultiplier * (Target.Quality + 1); + GameModsConfig.Instance.NephalemRift.ProgressMultiplier * (Target.Quality + 1); Player master = null; foreach (var plr3 in Target.World.Game.Players.Values) { if (plr3.PlayerIndex == 0) master = plr3; - if (GameServerConfig.Instance.NephalemRiftAutoFinish && Target.World.Monsters.Count(s => !s.Dead) <= GameServerConfig.Instance.NephalemRiftAutoFinishThreshold) Target.World.Game.ActiveNephalemProgress = 651; + if (GameModsConfig.Instance.NephalemRift.AutoFinish && Target.World.Monsters.Count(s => !s.Dead) <= GameModsConfig.Instance.NephalemRift.AutoFinishThreshold) Target.World.Game.ActiveNephalemProgress = 651; plr3.InGameClient.SendMessage(new SimpleMessage(Opcodes.KillCounterRefresh)); plr3.InGameClient.SendMessage(new FloatDataMessage(Opcodes.DungeonFinderProgressMessage) { @@ -711,7 +712,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads } - if (Target.Quality > 1 || FastRandom.Instance.Chance(GameServerConfig.Instance.NephalemRiftOrbsChance)) + if (Target.Quality > 1 || FastRandom.Instance.Chance(GameModsConfig.Instance.NephalemRift.OrbsChance)) { //spawn spheres for mining indicator for (int i = 0; i < Target.Quality + 1; i++) @@ -938,7 +939,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads // if seed is less than the drop rate, drop the item if (seed < rate * (1f + lootSpawnPlayer.Attributes[GameAttributes.Magic_Find]) - * GameServerConfig.Instance.RateDrop) + * GameModsConfig.Instance.Rate.Drop) { //Logger.Debug("rate: {0}", rate); var lootQuality = Target.World.Game.IsHardcore @@ -1223,7 +1224,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads if (player.World.Game.IsHardcore) { player.AddTimedAction(3f, (_) => player.Revive(player.CheckPointPosition)); - var toon = player.Toon.DBToon; + var toon = player.Toon.DbToon; toon.Deaths++; player.World.Game.GameDbSession.SessionUpdate(toon); } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Payloads/HitPayload.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Payloads/HitPayload.cs index 2d8f44a..c66a1f6 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Payloads/HitPayload.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/PowerSystem/Payloads/HitPayload.cs @@ -376,7 +376,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Payloads if (Target is Monster monster) { - TotalDamage *= 1 + plr.Attributes[GameAttributes.Damage_Percent_Bonus_Vs_Monster_Type, monster.MonsterType]; + TotalDamage *= 1 + plr.Attributes[GameAttributes.Damage_Percent_Bonus_Vs_Monster_Type, monster.MonsterTypeValue]; if (monster.Quality > 0) TotalDamage *= 1 + plr.Attributes[GameAttributes.Damage_Percent_Bonus_Vs_Elites]; diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/ActI.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/ActI.cs index 8b55eca..109c8c4 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/ActI.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/ActI.cs @@ -244,16 +244,23 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem //AddFollower(this.Game.GetWorld(71150), 4580); Game.AddOnLoadWorldAction(WorldSno.trout_town, () => { - // TODO: CHeck for possible removing outer adding - Game.AddOnLoadWorldAction(WorldSno.trout_town, () => + if (Game.CurrentQuest == 72095 && Game.CurrentStep is -1 or 7) { - if (Game.CurrentQuest == 72095) - if (Game.CurrentStep == -1 || Game.CurrentStep == 7) - { - AddFollower(Game.GetWorld(WorldSno.trout_town), ActorSno._leah); - } - }); - + // var world = Game.GetWorld(WorldSno.trout_town); + // Logger.QuestStep("Adding leah follower"); + // // teleport leah + // var actor = world.GetActorBySNO(ActorSno._leah); + // if (actor != null) + // { + // actor.Teleport(Game.FirstPlayer().Position.Around(2f)); + // } + AddUniqueFollower(Game.GetWorld(WorldSno.trout_town), ActorSno._leah); + } + else + { + Logger.QuestStep($"Can't add leah follower: {Game.CurrentQuest} / {Game.CurrentStep}"); + } + }); } }); @@ -265,6 +272,7 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem NextStep = 49, OnAdvance = () => { //go to gates + AddUniqueFollower(Game.GetWorld(WorldSno.trout_town), ActorSno._leah); var world = Game.GetWorld(WorldSno.trout_town); StartConversation(world, 166678); ListenProximity(ActorSno._trout_oldtristram_exit_gate, new Advance()); @@ -409,12 +417,16 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem Saveable = true, NextStep = 23, OnAdvance = () => - { //go to church + { + //go to church var world = Game.GetWorld(WorldSno.trout_town); ListenProximity(ActorSno._trdun_cath_cathedraldoorexterior, new Advance()); var leah = world.GetActorBySNO(ActorSno._leah); if (leah != null) + { leah.Hidden = false; + leah.SetVisible(true); + } SetActorVisible(world, ActorSno._tristram_mayor, false); var cart = world.GetActorBySNO(ActorSno._trout_newtristram_blocking_cart, true); if (cart != null) @@ -482,6 +494,7 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem OnAdvance = () => { //go with Cain Game.CurrentEncounter.Activated = false; + StartConversation(Game.GetWorld(WorldSno.trdun_cain_intro), 72496); ListenTeleport(19938, new Advance()); } @@ -504,19 +517,17 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem StartConversation(tristramWorld, 72498); }); //StartConversation(this.Game.GetWorld(71150), 72496); - var leah = tristramWorld.GetActorBySNO(ActorSno._leah, true); - if (leah == null) + DestroyFollower(ActorSno._leah); + + var leah = tristramWorld.GetActorsBySNO(ActorSno._leah); + if (!leah.Any()) { - leah = tristramWorld.GetActorBySNO(ActorSno._leah, false); - if (leah != null) - { - leah.Hidden = false; - leah.SetVisible(true); - } - else - { - Logger.Warn($"Leah not found in world {tristramWorld.SNO.ToString()} - quest 72095/step 32"); - } + Logger.Warn("Leah not found in world."); + } + foreach (var l in leah) + { + l.Hidden = false; + l.SetVisible(true); } ListenConversation(198617, new Advance()); } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/QuestProgress.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/QuestProgress.cs index 30aaa07..157eea3 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/QuestProgress.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/QuestProgress.cs @@ -276,6 +276,12 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem return Game.Players.Values.First().Followers.Any(x => x.Value == sno); } + public void AddUniqueFollower(World world, ActorSno sno) + { + if (!HasFollower(sno)) + AddFollower(world, sno); + } + public void AddFollower(World world, ActorSno sno) { if (Game.Players.Count > 0) diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/SkillsSystem/SkillSet.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/SkillsSystem/SkillSet.cs index cb3bb92..e9ef9ca 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/SkillsSystem/SkillSet.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/SkillsSystem/SkillSet.cs @@ -26,7 +26,7 @@ namespace DiIiS_NA.GameServer.GSSystem.SkillsSystem ToonClass = toonClass; Player = player; // var dbToon = player.Toon.DBToon; - var dbActiveSkills = player.Toon.DBActiveSkills; + var dbActiveSkills = player.Toon.DbActiveSkills; ActiveSkills = new ActiveSkillSavedData[6] { new() @@ -82,7 +82,7 @@ namespace DiIiS_NA.GameServer.GSSystem.SkillsSystem public void UpdateSkills(int hotBarIndex, int SNOSkill, int SNORune, Toon toon) { Logger.MethodTrace(string.Format("Update index {0} skill {1} rune {2}", hotBarIndex, SNOSkill, SNORune)); - var dbActiveSkills = Player.Toon.DBActiveSkills; + var dbActiveSkills = Player.Toon.DbActiveSkills; switch (hotBarIndex) { case 0: @@ -127,7 +127,7 @@ namespace DiIiS_NA.GameServer.GSSystem.SkillsSystem public void UpdatePassiveSkills(Toon toon) { Logger.Debug("Update passive to {0} {1} {2} {3}", PassiveSkills[0], PassiveSkills[1], PassiveSkills[2], PassiveSkills[3]); - var dbActiveSkills = Player.Toon.DBActiveSkills; + var dbActiveSkills = Player.Toon.DbActiveSkills; dbActiveSkills.Passive0 = PassiveSkills[0]; dbActiveSkills.Passive1 = PassiveSkills[1]; dbActiveSkills.Passive2 = PassiveSkills[2]; diff --git a/src/DiIiS-NA/D3-GameServer/GameModsConfig.cs b/src/DiIiS-NA/D3-GameServer/GameModsConfig.cs new file mode 100644 index 0000000..17a76ff --- /dev/null +++ b/src/DiIiS-NA/D3-GameServer/GameModsConfig.cs @@ -0,0 +1,230 @@ +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.IO; +using System.Threading.Tasks; +using DiIiS_NA; +using DiIiS_NA.Core.Logging; +using DiIiS_NA.GameServer; +using Newtonsoft.Json; + +namespace DiIiS_NA.D3_GameServer; + +public class RateConfig +{ + public float GetDamageByDifficulty(int diff) + { + diff = Math.Clamp(diff, 0, 19); + return !DamageByDifficulty.ContainsKey(diff) ? 1f : DamageByDifficulty[diff]; + } + public Dictionary HealthByDifficulty { get; set; } = new() + { + [0] = 1.0f, [1] = 1.0f, [2] = 1.0f, [3] = 1.0f, [4] = 1.0f, [5] = 1.0f, + [6] = 1.0f, [7] = 1.0f, [8] = 1.0f, [9] = 1.0f, [10] = 1.0f, [11] = 1.0f, + [12] = 1.0f, [13] = 1.0f, [14] = 1.0f, [15] = 1.0f, [16] = 1.0f, + [17] = 1.0f, [18] = 1.0f, [19] = 1.0f, + }; + + public Dictionary DamageByDifficulty { get; set; } = new() + { + [0] = 1.0f, [1] = 1.0f, [2] = 1.0f, [3] = 1.0f, [4] = 1.0f, [5] = 1.0f, + [6] = 1.0f, [7] = 1.0f, [8] = 1.0f, [9] = 1.0f, [10] = 1.0f, [11] = 1.0f, + [12] = 1.0f, [13] = 1.0f, [14] = 1.0f, [15] = 1.0f, [16] = 1.0f, + [17] = 1.0f, [18] = 1.0f, [19] = 1.0f, + }; + public float Experience { get; set; } = 1; + public float Gold { get; set; } = 1; + public float Drop { get; set; } = 1; + public float ChangeDrop { get; set; } = 1; +} + +public class HealthConfig +{ + public float PotionRestorePercentage { get; set; } = 60f; + public float PotionCooldown { get; set; } = 30f; + public int ResurrectionCharges { get; set; } = 3; +} + +public class HealthDamageMultiplier +{ + public float HealthMultiplier { get; set; } = 1; + public float DamageMultiplier { get; set; } = 1; +} + +public class MonsterConfig +{ + public float AttacksPerSecond { get; set; } = 1.2f; + + public float HealthMultiplier { get; set; } = 1; + public float HealthBonusMultiplier { get; set; } = 1; + public float DamageMultiplier { get; set; } = 1; + + /// + /// Attack target range + /// + public float LookupRange { get; set; } = 80f; + + /// + /// Total health bonus multiplier that can be applied to a monster + /// + public float HealthBonusMultiplierCap { get; set; } = 1.025f; +} + +public class QuestConfig +{ + public bool AutoSave { get; set; } = false; + public bool UnlockAllWaypoints { get; set; } = false; +} + +public class PlayerMultiplierConfig +{ + public ParagonConfig Strength { get; set; } = new(1f); + public ParagonConfig Dexterity { get; set; } = new(1f); + public ParagonConfig Intelligence { get; set; } = new(1f); + public ParagonConfig Vitality { get; set; } = new(1f); +} +public class PlayerConfig +{ + public PlayerMultiplierConfig Multipliers = new(); +} + +public class ItemsConfig +{ + public UnidentifiedDrop UnidentifiedDropChances { get; set; } = new(); +} + +public class UnidentifiedDrop +{ + public float HighQuality { get; set; } = 30f; + public float NormalQuality { get; set; } = 5f; +} + +public class MinimapConfig +{ + public bool ForceVisibility { get; set; } = false; +} + +public class NephalemRiftConfig +{ + public float ProgressMultiplier { get; set; } = 1f; + public bool AutoFinish { get; set; } = false; + public int AutoFinishThreshold { get; set; } = 2; + public float OrbsChance { get; set; } = 0f; +} + +public class GameModsConfig +{ + public RateConfig Rate { get; set; } = new(); + public HealthConfig Health { get; set; } = new(); + public MonsterConfig Monster { get; set; } = new(); + public HealthDamageMultiplier Boss { get; set; } = new(); + public QuestConfig Quest { get; set; } = new(); + public PlayerConfig Player { get; set; } = new(); + public ItemsConfig Items { get; set; } = new(); + public MinimapConfig Minimap { get; set; } = new(); + public NephalemRiftConfig NephalemRift { get; set; } = new(); + + private static readonly Logger Logger = LogManager.CreateLogger(); + + public GameModsConfig() {} + + static GameModsConfig() + { + CreateInstance(); + } + + public static void ReloadSettings() + { + CreateInstance(); + } + + private static readonly object InstanceCreationLock = new(); + public static GameModsConfig Instance { get; private set; } + + private static void CreateInstance() + { + lock (InstanceCreationLock) + { + if (!File.Exists("config.mods.json")) + { + Instance = CreateDefaultFile(); + } + else + { + var content = File.ReadAllText("config.mods.json"); + if (content.TryFromJson(out GameModsConfig config, out Exception ex)) + { + Logger.Success("Game mods loaded successfully!"); + var @new = config.ToJson(Formatting.Indented); + File.WriteAllText(@"config.mods.json", @new); + Instance = config; + return; + } + + Logger.Fatal("An error occurred whilst loading $[white on red]$config.mods.json$[/]$ file. Please verify if the file is correct. Delete the file and try again."); + Program.Shutdown(ex); + } + } + } + + private static GameModsConfig CreateDefaultFile() + { + var migration = GameServerConfig.Instance; + File.WriteAllText("config.mods.json", new GameModsConfig().ToJson()); + Logger.Success("Game mods file created successfully!"); + return new GameModsConfig(); + } +} + +public static class JsonExtensions +{ + private const bool Indented = true; + + public static string ToJson(this object obj, Formatting? formatting = null) + { + return JsonConvert.SerializeObject(obj, formatting ?? (Indented ? Formatting.Indented : Formatting.None)); + } + + public static bool TryFromJson(this string obj, out T value) + where T: class, new() + { + try + { + value = obj.FromJson(); + return true; + } + catch (Exception ex) + { + value = default; + return false; + } + } + + public static bool TryFromJson(this string obj, out T value, out Exception exception) + where T: class, new() + { + try + { + value = obj.FromJson(); + exception = null; + return true; + } + catch (Exception ex) + { + value = default; + exception = ex; + return false; + } + } + + public static T FromJson(this string obj) + where T: class, new() + { + return JsonConvert.DeserializeObject(obj); + } + + public static dynamic FromJsonDynamic(this string obj) + { + return obj.FromJson(); + } +} \ No newline at end of file diff --git a/src/DiIiS-NA/D3-GameServer/GameServerConfig.cs b/src/DiIiS-NA/D3-GameServer/GameServerConfig.cs index 095569e..cdbb2e2 100644 --- a/src/DiIiS-NA/D3-GameServer/GameServerConfig.cs +++ b/src/DiIiS-NA/D3-GameServer/GameServerConfig.cs @@ -65,12 +65,13 @@ namespace DiIiS_NA.GameServer #endif set => Set(nameof(AfkDisconnect), value); } - + #region Game Mods /// /// Rate of experience gain. /// + [Obsolete("Use GameModsConfig instead.")] public float RateExp { get => GetFloat(nameof(RateExp), 1); @@ -80,6 +81,7 @@ namespace DiIiS_NA.GameServer /// /// Rate of gold gain. /// + [Obsolete("Use GameModsConfig instead.")] public float RateMoney { get => GetFloat(nameof(RateMoney), 1); @@ -89,12 +91,14 @@ namespace DiIiS_NA.GameServer /// /// Rate of item drop. /// + [Obsolete("Use GameModsConfig instead.")] public float RateDrop { get => GetFloat(nameof(RateDrop), 1); set => Set(nameof(RateDrop), value); } + [Obsolete("Use GameModsConfig instead.")] public float RateChangeDrop { get => GetFloat(nameof(RateChangeDrop), 1); @@ -104,6 +108,7 @@ namespace DiIiS_NA.GameServer /// /// Rate of monster's HP. /// + [Obsolete("Use GameModsConfig instead.")] public float RateMonsterHP { get => GetFloat(nameof(RateMonsterHP), 1); @@ -113,6 +118,7 @@ namespace DiIiS_NA.GameServer /// /// Rate of monster's damage. /// + [Obsolete("Use GameModsConfig instead.")] public float RateMonsterDMG { get => GetFloat(nameof(RateMonsterDMG), 1); @@ -122,6 +128,7 @@ namespace DiIiS_NA.GameServer /// /// Percentage that a unique, legendary, set or special item created is unidentified /// + [Obsolete("Use GameModsConfig instead.")] public float ChanceHighQualityUnidentified { get => GetFloat(nameof(ChanceHighQualityUnidentified), 30f); @@ -131,6 +138,7 @@ namespace DiIiS_NA.GameServer /// /// Percentage that a normal item created is unidentified /// + [Obsolete("Use GameModsConfig instead.")] public float ChanceNormalUnidentified { get => GetFloat(nameof(ChanceNormalUnidentified), 5f); @@ -140,6 +148,7 @@ namespace DiIiS_NA.GameServer /// /// Resurrection charges on changing worlds /// + [Obsolete("Use GameModsConfig instead.")] public int ResurrectionCharges { get => GetInt(nameof(ResurrectionCharges), 3); @@ -149,6 +158,7 @@ namespace DiIiS_NA.GameServer /// /// Boss Health Multiplier /// + [Obsolete("Use GameModsConfig instead.")] public float BossHealthMultiplier { get => GetFloat(nameof(BossHealthMultiplier), 6f); @@ -158,6 +168,7 @@ namespace DiIiS_NA.GameServer /// /// Boss Damage Multiplier /// + [Obsolete("Use GameModsConfig instead.")] public float BossDamageMultiplier { get => GetFloat(nameof(BossDamageMultiplier), 3f); @@ -167,6 +178,7 @@ namespace DiIiS_NA.GameServer /// /// Whether to bypass the quest's settings of "Saveable" to TRUE (unless in OpenWorld) /// + [Obsolete("Use GameModsConfig instead.")] public bool AutoSaveQuests { get => GetBoolean(nameof(AutoSaveQuests), false); @@ -176,6 +188,7 @@ namespace DiIiS_NA.GameServer /// /// Progress gained when killing a monster in Nephalem Rifts /// + [Obsolete("Use GameModsConfig instead.")] public float NephalemRiftProgressMultiplier { get => GetFloat(nameof(NephalemRiftProgressMultiplier), 1f); @@ -185,6 +198,7 @@ namespace DiIiS_NA.GameServer /// /// How much a health potion heals in percentage /// + [Obsolete("Use GameModsConfig instead.")] public float HealthPotionRestorePercentage { get => GetFloat(nameof(HealthPotionRestorePercentage), 60f); @@ -194,6 +208,7 @@ namespace DiIiS_NA.GameServer /// /// Cooldown (in seconds) to use a health potion again. /// + [Obsolete("Use GameModsConfig instead.")] public float HealthPotionCooldown { get => GetFloat(nameof(HealthPotionCooldown), 30f); @@ -203,6 +218,7 @@ namespace DiIiS_NA.GameServer /// /// Unlocks all waypoints in the campaign. /// + [Obsolete("Use GameModsConfig instead.")] public bool UnlockAllWaypoints { get => GetBoolean(nameof(UnlockAllWaypoints), false); @@ -212,6 +228,7 @@ namespace DiIiS_NA.GameServer /// /// Strength multiplier when you're not a paragon. /// + [Obsolete("Use GameModsConfig instead.")] public float StrengthMultiplier { get => GetFloat(nameof(StrengthMultiplier), 1f); @@ -221,6 +238,7 @@ namespace DiIiS_NA.GameServer /// /// Strength multiplier when you're a paragon. /// + [Obsolete("Use GameModsConfig instead.")] public float StrengthParagonMultiplier { get => GetFloat(nameof(StrengthParagonMultiplier), 1f); @@ -230,6 +248,7 @@ namespace DiIiS_NA.GameServer /// /// Dexterity multiplier when you're not a paragon. /// + [Obsolete("Use GameModsConfig instead.")] public float DexterityMultiplier { get => GetFloat(nameof(DexterityMultiplier), 1f); @@ -239,6 +258,7 @@ namespace DiIiS_NA.GameServer /// /// Dexterity multiplier when you're a paragon. /// + [Obsolete("Use GameModsConfig instead.")] public float DexterityParagonMultiplier { get => GetFloat(nameof(DexterityParagonMultiplier), 1f); @@ -248,6 +268,7 @@ namespace DiIiS_NA.GameServer /// /// Intelligence multiplier when you're not a paragon. /// + [Obsolete("Use GameModsConfig instead.")] public float IntelligenceMultiplier { get => GetFloat(nameof(IntelligenceMultiplier), 1f); @@ -257,6 +278,7 @@ namespace DiIiS_NA.GameServer /// /// Intelligence multiplier when you're a paragon. /// + [Obsolete("Use GameModsConfig instead.")] public float IntelligenceParagonMultiplier { get => GetFloat(nameof(IntelligenceParagonMultiplier), 1f); @@ -266,6 +288,7 @@ namespace DiIiS_NA.GameServer /// /// Vitality multiplier when you're not a paragon. /// + [Obsolete("Use GameModsConfig instead.")] public float VitalityMultiplier { get => GetFloat(nameof(VitalityMultiplier), 1f); @@ -275,6 +298,7 @@ namespace DiIiS_NA.GameServer /// /// Vitality multiplier when you're a paragon. /// + [Obsolete("Use GameModsConfig instead.")] public float VitalityParagonMultiplier { get => GetFloat(nameof(VitalityParagonMultiplier), 1f); @@ -284,6 +308,7 @@ namespace DiIiS_NA.GameServer /// /// Auto finishes nephalem rift when there's or less monsters left. /// + [Obsolete("Use GameModsConfig instead.")] public bool NephalemRiftAutoFinish { get => GetBoolean(nameof(NephalemRiftAutoFinish), false); @@ -293,6 +318,7 @@ namespace DiIiS_NA.GameServer /// /// If is enabled, this is the threshold. /// + [Obsolete("Use GameModsConfig instead.")] public int NephalemRiftAutoFinishThreshold { get => GetInt(nameof(NephalemRiftAutoFinishThreshold), 2); @@ -302,6 +328,7 @@ namespace DiIiS_NA.GameServer /// /// Nephalem Rifts chance of spawning a orb. /// + [Obsolete("Use GameModsConfig instead.")] public float NephalemRiftOrbsChance { get => GetFloat(nameof(NephalemRiftOrbsChance), 0f); @@ -311,6 +338,7 @@ namespace DiIiS_NA.GameServer /// /// Forces the game to reveal all the map. /// + [Obsolete("Use GameModsConfig instead.")] public bool ForceMinimapVisibility { get => GetBoolean(nameof(ForceMinimapVisibility), false); @@ -318,6 +346,7 @@ namespace DiIiS_NA.GameServer } #endregion + public static GameServerConfig Instance { get; } = new(); private GameServerConfig() : base("Game-Server") diff --git a/src/DiIiS-NA/D3-GameServer/ParagonMod.cs b/src/DiIiS-NA/D3-GameServer/ParagonMod.cs new file mode 100644 index 0000000..7732c58 --- /dev/null +++ b/src/DiIiS-NA/D3-GameServer/ParagonMod.cs @@ -0,0 +1,16 @@ +public class ParagonConfig +{ + public T Normal { get; set; } + public T Paragon { get; set; } + + public ParagonConfig() {} + public ParagonConfig(T defaultValue) : this(defaultValue, defaultValue) + { + } + + public ParagonConfig(T normal, T paragon) + { + Normal = normal; + Paragon = paragon; + } +} \ No newline at end of file diff --git a/src/DiIiS-NA/Program.cs b/src/DiIiS-NA/Program.cs index 8fe93e0..1a83caf 100644 --- a/src/DiIiS-NA/Program.cs +++ b/src/DiIiS-NA/Program.cs @@ -33,8 +33,10 @@ using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; using DiIiS_NA.Core.Extensions; +using DiIiS_NA.D3_GameServer; using Spectre.Console; using Environment = System.Environment; +using FluentNHibernate.Utils; namespace DiIiS_NA { @@ -47,12 +49,12 @@ namespace DiIiS_NA } class Program { - private static readonly Logger Logger = LogManager.CreateLogger("BZ.Net"); + private static readonly Logger Logger = LogManager.CreateLogger("Blizzless"); public static readonly DateTime StartupTime = DateTime.Now; public static BattleBackend BattleBackend { get; set; } public bool GameServersAvailable = true; - public const int MaxLevel = 70; + public const int MAX_LEVEL = 70; public static GameServer.ClientSystem.GameServer GameServer; public static Watchdog Watchdog; @@ -65,42 +67,54 @@ namespace DiIiS_NA public static string RestServerIp = RestConfig.Instance.IP; public static string PublicGameServerIp = DiIiS_NA.GameServer.NATConfig.Instance.PublicIP; - public static int Build => 30; - public static int Stage => 2; + public const int BUILD = 30; + public const int STAGE = 3; public static TypeBuildEnum TypeBuild => TypeBuildEnum.Beta; - private static bool DiabloCoreEnabled = DiIiS_NA.GameServer.GameServerConfig.Instance.CoreActive; + private static bool _diabloCoreEnabled = DiIiS_NA.GameServer.GameServerConfig.Instance.CoreActive; - static async Task StartAsync() + private static readonly CancellationTokenSource CancellationTokenSource = new(); + public static readonly CancellationToken Token = CancellationTokenSource.Token; + public static void Cancel() => CancellationTokenSource.Cancel(); + public static void CancelAfter(TimeSpan span) => CancellationTokenSource.CancelAfter(span); + public static bool IsCancellationRequested() => CancellationTokenSource.IsCancellationRequested; + + public void MergeCancellationWith(params CancellationToken[] tokens) => + CancellationTokenSource.CreateLinkedTokenSource(tokens); + static void WriteBanner() + { + void RightTextRule(string text, string ruleStyle) => AnsiConsole.Write(new Rule(text).RuleStyle(ruleStyle)); + string Url(string url) => $"[link={url}]{url}[/]"; + RightTextRule("[dodgerblue1]Blizz[/][deepskyblue2]less[/]", "steelblue1"); + RightTextRule($"[dodgerblue3]Build [/][deepskyblue3]{BUILD}[/]", "steelblue1_1"); + RightTextRule($"[dodgerblue3]Stage [/][deepskyblue3]{STAGE}[/]", "steelblue1_1"); + RightTextRule($"[deepskyblue3]{TypeBuild}[/]", "steelblue1_1"); + RightTextRule($"Diablo III [red]RoS 2.7.4.84161[/] - {Url("https://github.com/blizzless/blizzless-diiis")}", + "red"); + AnsiConsole.MarkupLine(""); + AnsiConsole.MarkupLine(""); + } + + static async Task StartAsync(string[] args) { AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler; DbProviderFactories.RegisterFactory("Npgsql", NpgsqlFactory.Instance); Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - string name = $"Blizzless: Build {Build}, Stage: {Stage} - {TypeBuild}"; + string name = $"Blizzless: Build {BUILD}, Stage: {STAGE} - {TypeBuild}"; SetTitle(name); - Maximize(); - AnsiConsole.Write(new Rule("[dodgerblue1]Blizz[/][deepskyblue2]less[/]").RuleStyle("steelblue1")); - AnsiConsole.Write(new Rule($"[dodgerblue3]Build [/][deepskyblue3]{Build}[/]").RightJustified() - .RuleStyle("steelblue1_1")); - AnsiConsole.Write(new Rule($"[dodgerblue3]Stage [/][deepskyblue3]{Stage}[/]").RightJustified() - .RuleStyle("steelblue1_1")); - AnsiConsole.Write(new Rule($"[deepskyblue3]{TypeBuild}[/]").RightJustified().RuleStyle("steelblue1_1")); - AnsiConsole.Write( - new Rule( - $"Diablo III [red]RoS 2.7.4.84161[/] - [link=https://github.com/blizzless/blizzless-diiis]https://github.com/blizzless/blizzless-diiis[/]") - .RuleStyle("red")); - - AnsiConsole.MarkupLine(""); - Console.WriteLine(); - + if (LogConfig.Instance.Targets.Any(x => x.MaximizeWhenEnabled && x.Enabled)) + Maximize(); + WriteBanner(); InitLoggers(); - #if DEBUG - DiabloCoreEnabled = true; + _diabloCoreEnabled = true; Logger.Info("Forcing Diablo III Core to be $[green]$enabled$[/]$ on debug mode."); +#else + if (!_diabloCoreEnabled) + Logger.Warn("Diablo III Core is $[red]$disabled$[/]$."); #endif - + var mod = GameModsConfig.Instance; #pragma warning disable CS4014 Task.Run(async () => #pragma warning restore CS4014 @@ -122,6 +136,9 @@ namespace DiIiS_NA $"Memory: {totalMemory:0.000} GB | " + $"CPU Time: {cpuTime.ToSmallText()} | " + $"Uptime: {uptime.ToSmallText()}"; + + if (IsCancellationRequested()) + text = "SHUTTING DOWN: " + text; if (SetTitle(text)) await Task.Delay(1000); else @@ -192,7 +209,7 @@ namespace DiIiS_NA GuildManager.PreLoadGuilds(); Logger.Info("Loading Diablo III - Core..."); - if (DiabloCoreEnabled) + if (_diabloCoreEnabled) { if (!MPQStorage.Initialized) { @@ -225,7 +242,7 @@ namespace DiIiS_NA BattleBackend = new BattleBackend(loginConfig.BindIP, loginConfig.WebPort); //Diablo 3 Game-Server - if (DiabloCoreEnabled) + if (_diabloCoreEnabled) StartGameServer(); else Logger.Fatal("Game server is disabled in the configs."); @@ -238,28 +255,36 @@ namespace DiIiS_NA IChannel boundChannel = await serverBootstrap.BindAsync(loginConfig.Port); - Logger.Info( - "$[bold red3_1]$Tip:$[/]$ graceful shutdown with $[red3_1]$CTRL+C$[/]$ or $[red3_1]$!q[uit]$[/]$ or $[red3_1]$!exit$[/]$."); - Logger.Info("$[bold red3_1]$" + - "Tip:$[/]$ SNO breakdown with $[red3_1]$!sno$[/]$ $[red3_1]$$[/]$."); - while (true) + Logger.Info("$[bold deeppink4]$Gracefully$[/]$ shutdown with $[red3_1]$CTRL+C$[/]$ or $[deeppink4]$!q[uit]$[/]$."); + Logger.Info("{0}", IsCancellationRequested()); + while (!IsCancellationRequested()) { var line = Console.ReadLine(); - if (line is null or "!q" or "!quit" or "!exit") + if(line == null){ + continue; + } + if (line == "!q" || line == "!quit" || line == "!exit") + { + Logger.Info("Break !quit"); break; - if (line is "!cls" or "!clear" or "cls" or "clear") + } + + if (line == "!cls" || line == "!clear" || line == "cls" || line == "clear") { AnsiConsole.Clear(); AnsiConsole.Cursor.SetPosition(0, 0); continue; } - if (line.ToLower().StartsWith("!sno")) + if (line.StartsWith("!sno", StringComparison.OrdinalIgnoreCase)) { if (IsTargetEnabled("ansi")) Console.Clear(); - MPQStorage.Data.SnoBreakdown(line.ToLower().Equals("!sno 1") || - line.ToLower().Equals("!sno true")); + + MPQStorage.Data.SnoBreakdown( + line.Equals("!sno 1", StringComparison.OrdinalIgnoreCase) || + line.Equals("!sno true", StringComparison.OrdinalIgnoreCase) + ); continue; } @@ -268,56 +293,76 @@ namespace DiIiS_NA if (PlayerManager.OnlinePlayers.Count > 0) { + Logger.Success("Gracefully shutting down..."); Logger.Info( $"Server is shutting down in 1 minute, $[blue]${PlayerManager.OnlinePlayers.Count} players$[/]$ are still online."); PlayerManager.SendWhisper("Server is shutting down in 1 minute."); + await Task.Delay(TimeSpan.FromMinutes(1)); } - Shutdown(delay: 25); + Shutdown(); } catch (Exception e) { - Shutdown(e, delay: 200); + Logger.Info(e.ToString()); + Shutdown(e); } finally { + Logger.Trace("Shutdown in progress !"); await Task.WhenAll( boss.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)), worker.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1))); } } - private static void Shutdown(Exception exception = null, int delay = 200) + private static bool _shuttingDown = false; + public static void Shutdown(Exception exception = null) + { - // if (!IsTargetEnabled("ansi")) + Logger.Trace("Shutdown here"); + Logger.Trace("Stack trace at shutdown: " + Environment.StackTrace); // Log the stack trace + if (_shuttingDown) return; + _shuttingDown = true; + if (!IsCancellationRequested()) + Cancel(); + + AnsiTarget.StopIfRunning(IsTargetEnabled("ansi")); + if (exception != null) { - AnsiTarget.StopIfRunning(); - if (exception != null) + AnsiConsole.WriteLine( + "An unhandled exception occured at initialization. Please report this to the developers."); + AnsiConsole.WriteException(exception); + } + + AnsiConsole.Progress().Start(ctx => + { + var task = ctx.AddTask("[darkred_1]Shutting down[/] [white]in[/] [red underline]10 seconds[/]"); + for (int i = 1; i < 11; i++) { - AnsiConsole.WriteLine("An unhandled exception occured at initialization. Please report this to the developers."); - AnsiConsole.WriteException(exception); - } - AnsiConsole.Progress().Start(ctx => - { - var task = ctx.AddTask("[red]Shutting down...[/]"); - for (int i = 0; i < 100; i++) + task.Description = $"[darkred_1]Shutting down[/] [white]in[/] [red underline]{11 - i} seconds[/]"; + for (int j = 0; j < 10; j++) { task.Increment(1); - Thread.Sleep(delay); + Thread.Sleep(100); } - }); - } - Environment.Exit(-1); + } + + task.Description = $"[darkred_1]Shutting down now.[/]"; + task.StopTask(); + }); + + Environment.Exit(exception is null ? 0 : -1); } - [HandleProcessCorruptedStateExceptions] - [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)] - static async Task Main() + static async Task Main(string[] args) { + args ??= Array.Empty(); + try { - await StartAsync(); + await StartAsync(args); } catch (Exception ex) { @@ -326,7 +371,6 @@ namespace DiIiS_NA } [SecurityCritical] - [HandleProcessCorruptedStateExceptionsAttribute] private static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs e) { var ex = e.ExceptionObject as Exception; @@ -347,45 +391,25 @@ namespace DiIiS_NA if (TargetsEnabled("ansi") > 1 || (IsTargetEnabled("console") && IsTargetEnabled("ansi"))) { - AnsiConsole.MarkupLine("[underline red on white]Fatal:[/] [red]You can't use both ansi and console targets at the same time, nor have more than one ansi target.[/]"); - AnsiConsole.Progress().Start(ctx => - { - var sd = ctx.AddTask("[red3_1]Shutting down[/]"); - for (int i = 0; i < 100; i++) - { - sd.Increment(1); - Thread.Sleep(25); - } - }); - Environment.Exit(-1); + AnsiConsole.MarkupLine("[underline red on white]Fatal:[/] [red]It is impossible to have both ANSI and Console targets activated concurrently.[/]"); + Shutdown(); } foreach (var targetConfig in LogConfig.Instance.Targets) { if (!targetConfig.Enabled) continue; - LogTarget target = null; - switch (targetConfig.Target.ToLower()) + LogTarget target = targetConfig.Target.ToLower() switch { - case "ansi": - target = new AnsiTarget( - targetConfig.MinimumLevel, - targetConfig.MaximumLevel, - targetConfig.IncludeTimeStamps, - targetConfig.TimeStampFormat); - break; - case "console": - target = new ConsoleTarget(targetConfig.MinimumLevel, targetConfig.MaximumLevel, - targetConfig.IncludeTimeStamps, - targetConfig.TimeStampFormat); - break; - case "file": - target = new FileTarget(targetConfig.FileName, targetConfig.MinimumLevel, - targetConfig.MaximumLevel, targetConfig.IncludeTimeStamps, - targetConfig.TimeStampFormat, - targetConfig.ResetOnStartup); - break; - } + "ansi" => new AnsiTarget(targetConfig.MinimumLevel, targetConfig.MaximumLevel, + targetConfig.IncludeTimeStamps, targetConfig.TimeStampFormat), + "console" => new ConsoleTarget(targetConfig.MinimumLevel, targetConfig.MaximumLevel, + targetConfig.IncludeTimeStamps, targetConfig.TimeStampFormat), + "file" => new FileTarget(targetConfig.FileName, targetConfig.MinimumLevel, + targetConfig.MaximumLevel, targetConfig.IncludeTimeStamps, targetConfig.TimeStampFormat, + targetConfig.ResetOnStartup), + _ => null + }; if (target != null) LogManager.AttachLogTarget(target); @@ -412,9 +436,10 @@ namespace DiIiS_NA } else { - Logger.Info("Discord bot Disabled.."); + Logger.Trace("Discord bot Disabled.."); } DiIiS_NA.GameServer.GSSystem.GeneratorsSystem.SpawnGenerator.RegenerateDensity(); + Logger.Trace("We are here first"); DiIiS_NA.GameServer.ClientSystem.GameServer.GSBackend = new GsBackend(LoginServerConfig.Instance.BindIP, LoginServerConfig.Instance.WebPort); } @@ -432,7 +457,6 @@ namespace DiIiS_NA } [DllImport("kernel32.dll", ExactSpelling = true)] - static extern IntPtr GetConsoleWindow(); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] @@ -444,7 +468,6 @@ namespace DiIiS_NA const int RESTORE = 9; private static void Maximize() { - // if it's running on windows try { if (Environment.OSVersion.Platform == PlatformID.Win32NT) diff --git a/src/DiIiS-NA/REST/Extensions/DataExtensions.cs b/src/DiIiS-NA/REST/Extensions/DataExtensions.cs index dc1d6d2..7b82ffd 100644 --- a/src/DiIiS-NA/REST/Extensions/DataExtensions.cs +++ b/src/DiIiS-NA/REST/Extensions/DataExtensions.cs @@ -136,9 +136,7 @@ namespace DiIiS_NA.REST.Extensions public static void Swap(ref T left, ref T right) { - T temp = left; - left = right; - right = temp; + (left, right) = (right, left); } #region Strings diff --git a/src/DiIiS-NA/REST/RestSession.cs b/src/DiIiS-NA/REST/RestSession.cs index 4e53e80..a2d2208 100644 --- a/src/DiIiS-NA/REST/RestSession.cs +++ b/src/DiIiS-NA/REST/RestSession.cs @@ -88,7 +88,7 @@ namespace DiIiS_NA.REST void HandleInfoRequest(HttpHeader request) { SendResponseHtml(HttpCode.OK, "Welcome to BlizzLess.Net" + - "\nBuild " + Program.Build + + "\nBuild " + Program.BUILD + "\nSupport: 2.7.4"); } diff --git a/src/DiIiS-NA/REST/SocketBase.cs b/src/DiIiS-NA/REST/SocketBase.cs index 148381a..fbaa7ca 100644 --- a/src/DiIiS-NA/REST/SocketBase.cs +++ b/src/DiIiS-NA/REST/SocketBase.cs @@ -45,16 +45,14 @@ namespace DiIiS_NA.REST try { - using (var socketEventargs = new SocketAsyncEventArgs()) - { - socketEventargs.SetBuffer(_receiveBuffer, 0, _receiveBuffer.Length); - socketEventargs.Completed += (sender, args) => ReadHandlerInternal(args); - socketEventargs.SocketFlags = SocketFlags.None; - socketEventargs.RemoteEndPoint = _socket.RemoteEndPoint; + using var socketEventArgs = new SocketAsyncEventArgs(); + socketEventArgs.SetBuffer(_receiveBuffer, 0, _receiveBuffer.Length); + socketEventArgs.Completed += (sender, args) => ReadHandlerInternal(args); + socketEventArgs.SocketFlags = SocketFlags.None; + socketEventArgs.RemoteEndPoint = _socket.RemoteEndPoint; - if (!_socket.ReceiveAsync(socketEventargs)) - ReadHandlerInternal(socketEventargs); - } + if (!_socket.ReceiveAsync(socketEventArgs)) + ReadHandlerInternal(socketEventArgs); } catch (Exception ex) { diff --git a/src/DiIiS-NA/config.ini b/src/DiIiS-NA/config.ini index 764b0b4..51e7d7b 100644 --- a/src/DiIiS-NA/config.ini +++ b/src/DiIiS-NA/config.ini @@ -1,69 +1,118 @@ -; Settings for Bnet -[Battle-Server] -Enabled = true -BindIP = 127.0.0.1 -WebPort = 9800 -Port = 1119 -BindIPv6 = ::1 -MotdEnabled = true -Motd = Welcome to Blizzless Diablo 3! +; ========== +; Configuration File Template +; ========== +; This is a template configuration file which can be modified as desired. The following branches are available for your convenience: +; - Community branch (recommended): https://github.com/blizzless/blizzless-diiis/tree/community +; - Test-stable branch: https://github.com/blizzless/blizzless-diiis/ +; - Master branch: https://github.com/blizzless/blizzless-diiis/tree/master -; ------------------------ +; Battle Server Settings +[Battle-Server] +; Enable or disable the Battle Server +Enabled = true +; IP address on which the server will be bound +BindIP = 127.0.0.1 +; Port for web interactions +WebPort = 9800 +; Port for the server +Port = 1119 + +; Message of the Day (MotD) Settings +; - MotdEnabled: Toggles whether the Message of The Day (MotD) is enabled or not +; - MotdEnabledWhenWorldLoads: Determines if MotD should be displayed every time a new world is loaded for a player +; - Motd: Text displayed as the MotD +MotdEnabled = true +MotdEnabledWhenWorldLoads = false +Motd = Welcome to Blizzless D3! +; - Remote MotD Enabled: Enable receiving MotD from a remote URL via POST request with payload: { "GameAccountId": ulong, "ToonName": string, "WorldGlobalId": uint } +; - MotdRemoteUrl: Remote URL to send payload and receive string; falls back to Motd string if unavailable +MotdEnabledRemote = false +MotdRemoteUrl = https://your-site.local/yourmotd + +; IWServer Setting (Currently inactive) ; [IWServer] ; IWServer = false -; ------------------------ -; REST services for login (and others) +; REST Service Settings for Login and Other Functions [REST] IP = 127.0.0.1 -Public = true PublicIP = 127.0.0.1 -PORT = 80 +PORT = 83 +Public = false -; ------------------------ -; Game server options and game-mods. +; Game Server Settings [Game-Server] +; Enable or disable the game server Enabled = true +; Activate game server core functionality CoreActive = true +; IP address on which the game server will be bound BindIP = 127.0.0.1 +; Port for web interactions WebPort = 9001 +; Port for game server connections Port = 1345 +; IP address for IPv6 bindings BindIPv6 = ::1 +; DRLG Emulation status DRLGemu = true -; Modding of game + +; NAT (Network Address Translation) Settings +[NAT] +; Toggles the NAT functionality +Enabled = True +; Your public IP address to enable NAT +PublicIP = 127.0.0.1 + +; ========== +; Game Modding Configuration +; For documentation, please check https://github.com/blizzless/blizzless-diiis/blob/community/docs/game-world-settings.md +; Multipliers for various gameplay rates RateExp = 1 RateMoney = 1 RateDrop = 1 RateChangeDrop = 1 RateMonsterHP = 1 RateMonsterDMG = 1 -; Percentage that a unique, legendary, set or special item created is unidentified -ChanceHighQualityUnidentified = 80 -; Percentage that normal item created is unidentified + +; Quality and identification chances for items +ChanceHighQualityUnidentified = 30 ChanceNormalUnidentified = 5 -; Amount of times user can resurrect at corpse -ResurrectionCharges = 5 -BossHealthMultiplier = 2 -BossDamageMultiplier = 1 -AutoSaveQuests = true -; ------------------------ -; Network address translation -[NAT] -Enabled = True -PublicIP = 127.0.0.1 +; Boss health and damage multipliers +BossHealthMultiplier = 6 +BossDamageMultiplier = 3 -; ------------------------ -; Where the outputs should be. -; Best for visualization (default): AnsiLog (target: Ansi) -; Best for debugging: ConsoleLog (target: console) -; Best for packet analysis: PacketLog (target: file) -; Logging level (ordered): -; Rarely used: RenameAccountLog (0), ChatMessage (1), BotCommand (2), -; Useful: Debug (3), MethodTrace (4), Trace (5), -; Normal and human-readable: Info (6), Success (7), -; Errors: Warn (8), Error (9), Fatal (10), -; Network Logs: PacketDump (11) +; Nephalem Rift progress multiplier +NephalemRiftProgressMultiplier = 1 + +; Health potion mechanics +HealthPotionRestorePercentage = 60 +HealthPotionCooldown = 30 +ResurrectionCharges = 3 + +; Waypoint settings +UnlockAllWaypoints = false + +; Player attribute modifiers +StrengthMultiplier = 1 +StrengthParagonMultiplier = 1 +DexterityMultiplier = 1 +DexterityParagonMultiplier = 1 +IntelligenceMultiplier = 1 +IntelligenceParagonMultiplier = 1 +VitalityMultiplier = 1 +VitalityParagonMultiplier = 1 + +; Quest saving behavior +AutoSaveQuests = false + +; Minimap visibility settings +ForceMinimapVisibility = false + +; =================== +; Log Output Settings +; AnsiLog for visualization, ConsoleLog for debugging, and PacketLog for packet analysis [AnsiLog] Enabled = true @@ -76,8 +125,8 @@ MaximumLevel = Fatal Enabled = false Target = Console IncludeTimeStamps = true -MinimumLevel = Debug -MaximumLevel = PacketDump +MinimumLevel = MethodTrace +MaximumLevel = Fatal [PacketLog] Enabled = true diff --git a/src/DiIiS-NA/config.mods.json b/src/DiIiS-NA/config.mods.json new file mode 100644 index 0000000..3c6436e --- /dev/null +++ b/src/DiIiS-NA/config.mods.json @@ -0,0 +1,106 @@ +{ + "Rate": { + "HealthByDifficulty": { + "0": 1.0, + "1": 1.0, + "2": 1.0, + "3": 1.0, + "4": 1.0, + "5": 1.0, + "6": 1.0, + "7": 1.0, + "8": 1.0, + "9": 1.0, + "10": 1.0, + "11": 1.0, + "12": 1.0, + "13": 1.0, + "14": 1.0, + "15": 1.0, + "16": 1.0, + "17": 1.0, + "18": 1.0, + "19": 1.0 + }, + "DamageByDifficulty": { + "0": 1.0, + "1": 1.0, + "2": 1.0, + "3": 1.0, + "4": 1.0, + "5": 1.0, + "6": 1.0, + "7": 1.0, + "8": 1.0, + "9": 1.0, + "10": 1.0, + "11": 1.0, + "12": 1.0, + "13": 1.0, + "14": 1.0, + "15": 1.0, + "16": 1.0, + "17": 1.0, + "18": 1.0, + "19": 1.0 + }, + "Experience": 1.0, + "Gold": 1.0, + "Drop": 1.0, + "ChangeDrop": 1.0 + }, + "Health": { + "PotionRestorePercentage": 60.0, + "PotionCooldown": 30.0, + "ResurrectionCharges": 5 + }, + "Monster": { + "AttacksPerSecond": 1.2, + "HealthMultiplier": 1.0, + "DamageMultiplier": 1.0, + "LookupRange": 100.0 + }, + "Boss": { + "HealthMultiplier": 2.0, + "DamageMultiplier": 1.0 + }, + "Quest": { + "AutoSave": true, + "UnlockAllWaypoints": false + }, + "Player": { + "Multipliers": { + "Strength": { + "Normal": 1.0, + "Paragon": 1.0 + }, + "Dexterity": { + "Normal": 1.0, + "Paragon": 1.0 + }, + "Intelligence": { + "Normal": 1.0, + "Paragon": 1.0 + }, + "Vitality": { + "Normal": 1.0, + "Paragon": 1.0 + } + } + }, + "Items": { + "UnidentifiedDropChances": { + "HighQuality": 80.0, + "NormalQuality": 5.0 + } + }, + "Minimap": { + "ForceVisibility": false + }, + "NephalemRift": { + "ProgressMultiplier": 1.0, + "AutoFinish": false, + "AutoFinishThreshold": 2, + "OrbsChance": 2.0 + } +} \ No newline at end of file diff --git a/src/DiIiS-NA/database.Account.config b/src/DiIiS-NA/database.Account.config index 9de7d15..ae5d775 100644 --- a/src/DiIiS-NA/database.Account.config +++ b/src/DiIiS-NA/database.Account.config @@ -16,4 +16,4 @@ false false - \ No newline at end of file + diff --git a/src/DiIiS-NA/database.Worlds.config b/src/DiIiS-NA/database.Worlds.config index 8545182..ddec9eb 100644 --- a/src/DiIiS-NA/database.Worlds.config +++ b/src/DiIiS-NA/database.Worlds.config @@ -15,4 +15,4 @@ false false - \ No newline at end of file +