diff --git a/apps/account-create/.formatter.exs b/apps/account-create/.formatter.exs new file mode 100644 index 000000000..921beec59 --- /dev/null +++ b/apps/account-create/.formatter.exs @@ -0,0 +1,7 @@ +# Used by "mix format" +[ + inputs: [ + ".formatter.exs", + "account.exs" + ] +] diff --git a/apps/account-create/Dockerfile b/apps/account-create/Dockerfile new file mode 100644 index 000000000..4a2537bbf --- /dev/null +++ b/apps/account-create/Dockerfile @@ -0,0 +1,10 @@ +FROM elixir:1.14-slim + +RUN mix local.hex --force && \ + mix local.rebar --force + +COPY account.exs /account.exs +COPY srp.exs /srp.exs +RUN chmod +x /account.exs + +CMD /account.exs diff --git a/apps/account-create/README.md b/apps/account-create/README.md new file mode 100644 index 000000000..37380e519 --- /dev/null +++ b/apps/account-create/README.md @@ -0,0 +1,102 @@ +# Account.exs + +Simple script to create an account for AzerothCore + +This script allows a server admin to create a user automatically when after the `dbimport` tool runs, without needed to open up the `worldserver` console. + +## How To Use + +### Pre-requisites + +- MySQL is running +- The authserver database (`acore_auth`, typically) has a table named `account` + +### Running + +```bash +$ elixir account.exs +``` + +### Configuration + +This script reads from environment variables in order to control which account it creates and the MySQL server it's communicating with + + +- `ACORE_USERNAME` Username for account, default "admin" +- `ACORE_PASSWORD` Password for account, default "admin" +- `ACORE_GM_LEVEL` GM Level for account, default 3 +- `MYSQL_DATABASE` Database name, default "acore_auth" +- `MYSQL_USERNAME` MySQL username, default "root" +- `MYSQL_PASSWORD` MySQL password, default "password" +- `MYSQL_PORT` MySQL Port, default 3306 +- `MYSQL_HOST` MySQL Host, default "localhost" + +To use these environment variables, execute the script like so: + +```bash +$ MYSQL_HOST=mysql \ + MYSQL_PASSWORD="fourthehoard" \ + ACORE_USERNAME=drekthar \ + ACORE_PASSWORD=securepass22 \ + elixir account.exs +``` + +This can also be used in a loop. Consider this csv file: + +```csv +user,pass,gm_level +admin,adminpass,2 +soapuser,soappass,3 +mainuser,userpass,0 +``` + +You can then loop over this csv file, and manage users like so: + +```bash +$ while IFS=, read -r user pass gm; do + ACORE_USERNAME=$user \ + ACORE_PASSWORD=$pass \ + GM_LEVEL=$gm \ + elixir account.exs + done <<< $(tail -n '+2' users.csv) +``` + +### Docker + +Running and building with docker is simple: + +```bash +$ docker build -t acore/account-create . +$ docker run \ + -e MYSQL_HOST=mysql \ + -v mix_cache:/root/.cache/mix/installs \ + acore/account-create +``` + +Note that the `MYSQL_HOST` is required to be set with the docker container, as the default setting targets `localhost`. + +### docker-compose + +A simple way to integrate this into a docker-compose file. + +This is why I wrote this script - an automatic way to have an admin account idempotently created on startup of the server. + +```yaml +services: + account-create: + image: acore/account-create:${DOCKER_IMAGE_TAG:-master} + build: + context: apps/account-create/ + dockerfile: apps/account-create/Dockerfile + environment: + MYSQL_HOST: ac-database + MYSQL_PASSWORD: ${DOCKER_DB_ROOT_PASSWORD:-password} + ACORE_USERNAME: ${ACORE_ROOT_ADMIN_ACCOUNT:-admin} + ACORE_PASSWORD: ${ACORE_ROOT_ADMIN_PASSWORD:-password} + volumes: + - mix_cache:/root/.cache/mix/installs + profiles: [local, app, db-import-local] + depends_on: + ac-db-import: + condition: service_completed_successfully +``` diff --git a/apps/account-create/account.exs b/apps/account-create/account.exs new file mode 100644 index 000000000..c3443025c --- /dev/null +++ b/apps/account-create/account.exs @@ -0,0 +1,134 @@ +#!/usr/bin/env elixir +# Execute this Elixir script with the below command +# +# $ ACORE_USERNAME=foo ACORE_PASSWORD=barbaz123 elixir account.exs +# +# Set environment variables for basic configuration +# +# ACORE_USERNAME - Username for account, default "admin" +# ACORE_PASSWORD - Password for account, default "admin" +# ACORE_GM_LEVEL - GM level for account +# MYSQL_DATABASE - Database name, default "acore_auth" +# MYSQL_USERNAME - MySQL username, default "root" +# MYSQL_PASSWORD - MySQL password, default "password" +# MYSQL_PORT - MySQL Port, default 3306 +# MYSQL_HOST - MySQL Host, default "localhost" + +# Install remote dependencies +[ + {:myxql, "~> 0.6.0"} +] +|> Mix.install() + +# Start the logger +Application.start(:logger) +require Logger + +# Constants +default_credential = "admin" +default_gm_level = "3" +account_access_comment = "Managed via account-create script" + +# Import srp functions +Code.require_file("srp.exs", Path.absname(__DIR__)) + +# Assume operator provided a "human-readable" name. +# The database stores usernames in all caps +username_lower = + System.get_env("ACORE_USERNAME", default_credential) + |> tap(&Logger.info("Account to create: #{&1}")) + +username = String.upcase(username_lower) + +password = System.get_env("ACORE_PASSWORD", default_credential) + +gm_level = System.get_env("ACORE_GM_LEVEL", default_gm_level) |> String.to_integer() + +if Range.new(0, 3) |> Enum.member?(gm_level) |> Kernel.not do + Logger.info("Valid ACORE_GM_LEVEL values are 0, 1, 2, and 3. The given value was: #{gm_level}.") +end + +{:ok, pid} = + MyXQL.start_link( + protocol: :tcp, + database: System.get_env("MYSQL_DATABASE", "acore_auth"), + username: System.get_env("MYSQL_USERNAME", "root"), + password: System.get_env("MYSQL_PASSWORD", "password"), + port: System.get_env("MYSQL_PORT", "3306") |> String.to_integer(), + hostname: System.get_env("MYSQL_HOST", "localhost") + ) + +Logger.info("MySQL connection created") + +Logger.info("Checking database for user #{username_lower}") + +# Check if user already exists in database +{:ok, result} = MyXQL.query(pid, "SELECT salt FROM account WHERE username=?", [username]) + +%{salt: salt, verifier: verifier} = + case result do + %{rows: [[salt | _] | _]} -> + Logger.info("Salt for #{username_lower} found in database") + # re-use the salt if the user exists in database + Srp.generate_stored_values(username, password, salt) + _ -> + Logger.info("Salt not found in database for #{username_lower}. Generating a new one") + Srp.generate_stored_values(username, password) + end + +Logger.info("New salt and verifier generated") + +# Insert values into DB, replacing the verifier if the user already exists +result = + MyXQL.query( + pid, + """ + INSERT INTO account + (`username`, `salt`, `verifier`) + VALUES + (?, ?, ?) + ON DUPLICATE KEY UPDATE verifier=? + """, + [username, salt, verifier, verifier] + ) + +case result do + {:error, %{message: message}} -> + File.write("fail.log", message) + + Logger.info( + "Account #{username_lower} failed to create. You can check the error message at fail.log." + ) + + exit({:shutdown, 1}) + + # if num_rows changed and last_insert_id == 0, it means the verifier matched. No change necessary + {:ok, %{num_rows: 1, last_insert_id: 0}} -> + Logger.info( + "Account #{username_lower} doesn't need to have its' password changed. You should be able to log in with that account" + ) + + {:ok, %{num_rows: 1}} -> + Logger.info( + "Account #{username_lower} has been created. You should now be able to login with that account" + ) + + {:ok, %{num_rows: 2}} -> + Logger.info( + "Account #{username_lower} has had its' password reset. You should now be able to login with that account" + ) +end + +# Set GM level to configured value +{:ok, _} = + MyXQL.query( + pid, + """ + INSERT INTO account_access + (`id`, `gmlevel`, `comment`) + VALUES + ((SELECT id FROM account WHERE username=?), ?, ?) + ON DUPLICATE KEY UPDATE gmlevel=?, comment=? + """, [username, gm_level, account_access_comment, gm_level, account_access_comment]) + +Logger.info("GM Level for #{username_lower} set to #{gm_level}") diff --git a/apps/account-create/srp.exs b/apps/account-create/srp.exs new file mode 100644 index 000000000..987a6eeb9 --- /dev/null +++ b/apps/account-create/srp.exs @@ -0,0 +1,59 @@ +defmodule Srp do + # Constants required in WoW's SRP6 implementation + @n <<137, 75, 100, 94, 137, 225, 83, 91, 189, 173, 91, 139, 41, 6, 80, 83, 8, 1, 177, 142, 191, + 191, 94, 143, 171, 60, 130, 135, 42, 62, 155, 183>> + @g <<7>> + @field_length 32 + + # Wrapper function + def generate_stored_values(username, password, salt \\ "") do + default_state() + |> generate_salt(salt) + |> calculate_x(username, password) + |> calculate_v() + end + + def default_state() do + %{n: @n, g: @g} + end + + # Generate salt if it's not defined + def generate_salt(state, "") do + salt = :crypto.strong_rand_bytes(32) + Map.merge(state, %{salt: salt}) + end + + # Don't generate salt if it's already defined + def generate_salt(state, salt) do + padded_salt = pad_binary(salt) + Map.merge(state, %{salt: padded_salt}) + end + + # Get h1 + def calculate_x(state, username, password) do + hash = :crypto.hash(:sha, String.upcase(username) <> ":" <> String.upcase(password)) + x = reverse(:crypto.hash(:sha, state.salt <> hash)) + Map.merge(state, %{x: x, username: username}) + end + + # Get h2 + def calculate_v(state) do + verifier = + :crypto.mod_pow(state.g, state.x, state.n) + |> reverse() + |> pad_binary() + + Map.merge(state, %{verifier: verifier}) + end + + defp pad_binary(blob) do + pad = @field_length - byte_size(blob) + <> + end + + defp reverse(binary) do + binary + |> :binary.decode_unsigned(:big) + |> :binary.encode_unsigned(:little) + end +end diff --git a/data/sql/updates/db_world/2023_06_22_00.sql b/data/sql/updates/db_world/2023_06_22_00.sql new file mode 100644 index 000000000..cf9ccabae --- /dev/null +++ b/data/sql/updates/db_world/2023_06_22_00.sql @@ -0,0 +1,5 @@ +-- DB update 2023_06_21_00 -> 2023_06_22_00 +-- +DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_murmur_touch', 'spell_shockwave_knockback'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(33686, 'spell_shockwave_knockback'); diff --git a/data/sql/updates/db_world/2023_06_23_00.sql b/data/sql/updates/db_world/2023_06_23_00.sql new file mode 100644 index 000000000..951b7688a --- /dev/null +++ b/data/sql/updates/db_world/2023_06_23_00.sql @@ -0,0 +1,4 @@ +-- DB update 2023_06_22_00 -> 2023_06_23_00 +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 818) AND (`source_type` = 0) AND (`id` IN (2)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(818, 0, 2, 0, 23, 0, 100, 0, 12544, 0, 10000, 10000, 0, 11, 12544, 64, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Mai\'Zoth - On Aura \'Frost Armor\' Missing - Cast \'Frost Armor\''); diff --git a/data/sql/updates/db_world/2023_06_23_01.sql b/data/sql/updates/db_world/2023_06_23_01.sql new file mode 100644 index 000000000..64069727d --- /dev/null +++ b/data/sql/updates/db_world/2023_06_23_01.sql @@ -0,0 +1,7 @@ +-- DB update 2023_06_23_00 -> 2023_06_23_01 +UPDATE `creature` SET `MovementType` = 2 WHERE `guid` IN (6974,6989,7210) AND `id1` IN (2718,2717,2907); +DELETE FROM `creature_addon` WHERE (`guid` IN (6974,6989,7210)); +INSERT INTO `creature_addon` (`guid`, `path_id`, `bytes2`) VALUES +(6974, 69740, 1), +(6989, 69890, 1), +(7210, 72100, 1); diff --git a/data/sql/updates/db_world/2023_06_24_00.sql b/data/sql/updates/db_world/2023_06_24_00.sql new file mode 100644 index 000000000..ec8c24358 --- /dev/null +++ b/data/sql/updates/db_world/2023_06_24_00.sql @@ -0,0 +1,5 @@ +-- DB update 2023_06_23_01 -> 2023_06_24_00 +-- +UPDATE `smart_scripts` SET `action_param2`=0 WHERE `entryorguid`=1651800 AND `source_type`=9 AND `id` IN (2, 6); + +UPDATE `creature_template` SET `faction`=7 WHERE `entry`=16534; diff --git a/data/sql/updates/db_world/2023_06_24_01.sql b/data/sql/updates/db_world/2023_06_24_01.sql new file mode 100644 index 000000000..ff95b80a4 --- /dev/null +++ b/data/sql/updates/db_world/2023_06_24_01.sql @@ -0,0 +1,3 @@ +-- DB update 2023_06_24_00 -> 2023_06_24_01 +-- Add extra flag 33554432 to several skeleton creatures in Auchenai Crypts to avoid chain pulling +UPDATE `creature_template` SET `flags_extra` = `flags_extra`|33554432 WHERE (`entry` IN (18700, 20317, 18521, 20315, 18524, 20298)); diff --git a/data/sql/updates/db_world/2023_06_24_02.sql b/data/sql/updates/db_world/2023_06_24_02.sql new file mode 100644 index 000000000..fdee7f7ed --- /dev/null +++ b/data/sql/updates/db_world/2023_06_24_02.sql @@ -0,0 +1,28 @@ +-- DB update 2023_06_24_01 -> 2023_06_24_02 +-- +DELETE FROM `npc_trainer` WHERE `SpellID` IN ( +39973, -- Frost Grenades +40274, -- Furious Gizmatic Goggles +41311, -- Justicebringer 2000 Specs +41312, -- Tankatronic Goggles +41314, -- Surestrike Goggles v2.0 +41315, -- Gadgetstorm Goggles +41316, -- Living Replicator Specs +41317, -- Deathblow X11 Goggles +41318, -- Wonderheal XT40 Shades +41319, -- Magnified Moon Specs +41320, -- Destruction Holo-gogs +41321 -- Powerheal 4000 Lens +); +INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`, `ReqSpell`) VALUES +(201013, 39973, 50000, 202, 335, 0, 0), +(201013, 40274, 50000, 202, 350, 0, 0), +(201013, 41311, 50000, 202, 350, 0, 0), +(201013, 41312, 50000, 202, 350, 0, 0), +(201013, 41314, 50000, 202, 350, 0, 0), +(201013, 41315, 50000, 202, 350, 0, 0), +(201013, 41316, 50000, 202, 350, 0, 0), +(201013, 41317, 50000, 202, 350, 0, 0), +(201013, 41318, 50000, 202, 350, 0, 0), +(201013, 41319, 50000, 202, 350, 0, 0), +(201013, 41320, 50000, 202, 350, 0, 0); diff --git a/data/sql/updates/db_world/2023_06_24_03.sql b/data/sql/updates/db_world/2023_06_24_03.sql new file mode 100644 index 000000000..2e60f72d7 --- /dev/null +++ b/data/sql/updates/db_world/2023_06_24_03.sql @@ -0,0 +1,6 @@ +-- DB update 2023_06_24_02 -> 2023_06_24_03 +-- +DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_capacitus_polarity_charge_aura'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(39088, 'spell_capacitus_polarity_charge_aura'), +(39091, 'spell_capacitus_polarity_charge_aura'); diff --git a/data/sql/updates/db_world/2023_06_24_04.sql b/data/sql/updates/db_world/2023_06_24_04.sql new file mode 100644 index 000000000..f45922aa5 --- /dev/null +++ b/data/sql/updates/db_world/2023_06_24_04.sql @@ -0,0 +1,4 @@ +-- DB update 2023_06_24_03 -> 2023_06_24_04 +DELETE FROM `npc_trainer` WHERE `SpellID` = 41321; +INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqSkillLine`, `ReqSkillRank`, `ReqLevel`, `ReqSpell`) VALUES +(201013, 41321, 50000, 202, 350, 0, 0); diff --git a/data/sql/updates/db_world/2023_06_24_05.sql b/data/sql/updates/db_world/2023_06_24_05.sql new file mode 100644 index 000000000..fabe9dd62 --- /dev/null +++ b/data/sql/updates/db_world/2023_06_24_05.sql @@ -0,0 +1,3 @@ +-- DB update 2023_06_24_04 -> 2023_06_24_05 +-- +UPDATE `creature_template` SET `ScriptName` = '' WHERE `ScriptName` = 'npc_ahune_frozen_core'; diff --git a/data/sql/updates/db_world/2023_06_24_06.sql b/data/sql/updates/db_world/2023_06_24_06.sql new file mode 100644 index 000000000..f7b059354 --- /dev/null +++ b/data/sql/updates/db_world/2023_06_24_06.sql @@ -0,0 +1,3 @@ +-- DB update 2023_06_24_05 -> 2023_06_24_06 +-- +UPDATE `creature_template` SET `ScriptName` = '' WHERE (`entry` = 16592); diff --git a/data/sql/updates/db_world/2023_06_26_00.sql b/data/sql/updates/db_world/2023_06_26_00.sql new file mode 100644 index 000000000..97fecc60e --- /dev/null +++ b/data/sql/updates/db_world/2023_06_26_00.sql @@ -0,0 +1,42 @@ +-- DB update 2023_06_24_06 -> 2023_06_26_00 +-- Shay Leafrunner - On Quest - Wandering Shay -- +UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE (`entry` = 7774); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 7774); +INSERT INTO `smart_scripts` VALUES +(7774, 0, 0, 0, 19, 0, 100, 0, 2845, 0, 0, 0, 0, 80, 777400, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - On Quest \'Wandering Shay\' Taken - Run Script'), +(7774, 0, 1, 0, 8, 0, 100, 0, 11402, 0, 0, 0, 0, 80, 777401, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - On Spellhit \'Shay`s Bell\' - Run Script'), +(7774, 0, 2, 0, 75, 0, 100, 0, 0, 7765, 7, 10000, 0, 80, 777402, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - On Distance To Creature - Run Script'), +(7774, 0, 3, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 80, 777403, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - On Just Died - Run Script'), +(7774, 0, 4, 0, 38, 0, 100, 0, 1, 1, 0, 0, 0, 67, 61, 30000, 35000, 60000, 65000, 100, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - On Data Set 1 1 - Create Timed Event'), +(7774, 0, 5, 6, 59, 0, 100, 0, 61, 0, 0, 0, 0, 73, 38, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - On Timed Event 61 Triggered - Trigger Timed Event 38'), +(7774, 0, 6, 7, 61, 0, 100, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - On Timed Event 61 Triggered - Stop Follow '), +(7774, 0, 7, 8, 61, 0, 100, 0, 0, 0, 0, 0, 0, 89, 15, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - On Data Set 1 1 - Start Random Movement'), +(7774, 0, 8, 9, 61, 0, 100, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - On Data Set 1 1 - Say Line 2'), +(7774, 0, 9, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - On Data Set 1 1 - Say Line 3'), +(7774, 0, 10, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 74, 61, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - On Respawn - Remove Timed Event 61'), +(7774, 0, 11, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 6, 2845, 0, 0, 0, 0, 0, 18, 10, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - On Just Died - Fail Quest \'Wandering Shay\''), +(7774, 0, 12, 0, 75, 0, 100, 1, 0, 7765, 10, 5000, 0, 1, 0, 0, 0, 0, 0, 0, 11, 7765, 10, 1, 0, 0, 0, 0, 0, 'Shay Leafrunner - On Distance To Creature - Say Line 0'); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` = 777400); +INSERT INTO `smart_scripts` VALUES +(777400, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 19, 768, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - Actionlist - Remove Flags Immune To Players & Immune To NPC\'s'), +(777400, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 29, 2, 3, 7765, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - Actionlist - Start Follow Invoker'), +(777400, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - Actionlist - Say Line 0'), +(777400, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 45, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - Actionlist - Set Data 1 1'); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` = 777401); +INSERT INTO `smart_scripts` VALUES +(777401, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 29, 2, 3, 7765, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - Actionlist - Start Follow Invoker'), +(777401, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - Actionlist - Say Line 1'); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` = 777402); +INSERT INTO `smart_scripts` VALUES +(777402, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 15, 2845, 0, 0, 0, 0, 0, 18, 10, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - Actionlist - Quest Credit \'Wandering Shay\''), +(777402, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - Actionlist - Say Line 4'); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` = 777403); +INSERT INTO `smart_scripts` VALUES +(777403, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 6, 2845, 0, 0, 0, 0, 0, 18, 10, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - Actionlist - Fail Quest \'Wandering Shay\''), +(777403, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 18, 768, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - Actionlist - Set Flags Immune To Players & Immune To NPC\'s'), +(777403, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 74, 61, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Shay Leafrunner - Actionlist - Remove Timed Event 61'); diff --git a/data/sql/updates/db_world/2023_06_26_01.sql b/data/sql/updates/db_world/2023_06_26_01.sql new file mode 100644 index 000000000..73e611877 --- /dev/null +++ b/data/sql/updates/db_world/2023_06_26_01.sql @@ -0,0 +1,331 @@ +-- DB update 2023_06_26_00 -> 2023_06_26_01 +-- +SET @OGUID := 76200; + +DELETE FROM `gameobject` WHERE `id` = 181288 AND `guid` BETWEEN @OGUID AND @OGUID+77; +INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`) VALUES +(@OGUID+0 , 181288, 0, 0, 0, 1, 1, -14376.7, 115.921, 1.4532, 2.11185, 0, 0, 0.870356, 0.492423, 180, 100, 1, '', 0), +(@OGUID+1 , 181288, 0, 0, 0, 1, 1, -14288.1, 61.8062, 0.68836, 1.37881, 0, 0, 0.636078, 0.771625, 180, 100, 1, '', 0), +(@OGUID+2 , 181288, 0, 0, 0, 1, 1, -10951.5, -3218.1, 41.3475, 1.91986, 0, 0, 0.819151, 0.573577, 180, 100, 1, '', 0), +(@OGUID+3 , 181288, 0, 0, 0, 1, 1, -10704.8, -1146.38, 24.7909, 2.09439, 0, 0, 0.866024, 0.500002, 180, 100, 1, '', 0), +(@OGUID+4 , 181288, 0, 0, 0, 1, 1, -10657.1, 1054.63, 32.6733, 2.47837, 0, 0, 0.945519, 0.325567, 180, 100, 1, '', 0), +(@OGUID+5 , 181288, 0, 0, 0, 1, 1, -10331.4, -3297.73, 21.9992, -2.89725, 0, 0, -0.992546, 0.121868, 180, 100, 1, '', 0), +(@OGUID+6 , 181288, 0, 0, 0, 1, 1, -9434.3, -2110.36, 65.8038, 0.349066, 0, 0, 0.173648, 0.984808, 180, 100, 1, '', 0), +(@OGUID+7 , 181288, 0, 0, 0, 1, 1, -9394.21, 37.5017, 59.882, 1.15192, 0, 0, 0.54464, 0.83867, 180, 100, 1, '', 0), +(@OGUID+8 , 181288, 0, 0, 0, 1, 1, -8245.62, -2623.9, 133.155, 4.04776, 0, 0, 0.899102, -0.43774, 300, 0, 1, '', 0), +(@OGUID+9 , 181288, 0, 0, 0, 1, 1, -7596.42, -2086.6, 125.17, -0.942478, 0, 0, -0.453991, 0.891006, 180, 100, 1, '', 0), +(@OGUID+10, 181288, 0, 0, 0, 1, 1, -6704.48, -2200.91, 248.609, 0.017453, 0, 0, 0.00872639, 0.999962, 180, 100, 1, '', 0), +(@OGUID+11, 181288, 0, 0, 0, 1, 1, -5404.93, -492.299, 395.597, -0.506145, 0, 0, -0.25038, 0.968148, 180, 100, 1, '', 0), +(@OGUID+12, 181288, 0, 0, 0, 1, 1, -5233.16, -2893.37, 337.286, -0.226893, 0, 0, -0.113203, 0.993572, 180, 100, 1, '', 0), +(@OGUID+13, 181288, 0, 0, 0, 1, 1, -3448.2, -938.102, 10.6583, 0.034907, 0, 0, 0.0174526, 0.999848, 180, 100, 1, '', 0), +(@OGUID+14, 181288, 0, 0, 0, 1, 1, -1211.6, -2676.88, 45.3612, -0.645772, 0, 0, -0.317305, 0.948324, 180, 100, 1, '', 0), +(@OGUID+15, 181288, 0, 0, 0, 1, 1, -1134.84, -3531.81, 51.0719, -0.820305, 0, 0, -0.398749, 0.91706, 180, 100, 1, '', 0), +(@OGUID+16, 181288, 0, 0, 0, 1, 1, -604.148, -545.813, 36.579, 0.698132, 0, 0, 0.34202, 0.939693, 180, 100, 1, '', 0), +(@OGUID+17, 181288, 0, 0, 0, 1, 1, -447.95, -4527.65, 8.59595, 1.53589, 0, 0, 0.694658, 0.71934, 180, 100, 1, '', 0), +(@OGUID+18, 181288, 0, 0, 0, 1, 1, -134.688, -802.767, 55.0147, -1.62316, 0, 0, -0.725376, 0.688353, 180, 100, 1, '', 0), +(@OGUID+19, 181288, 0, 0, 0, 1, 1, 188.243, -2132.53, 102.674, -1.37881, 0, 0, -0.636078, 0.771625, 180, 100, 1, '', 0), +(@OGUID+20, 181288, 0, 0, 0, 1, 1, 587.056, 1365.02, 90.4778, 2.6529, 0, 0, 0.970296, 0.241922, 180, 100, 1, '', 0), +(@OGUID+21, 181288, 0, 0, 0, 1, 1, 989.562, -1453.47, 61.0011, 4.9105, 0, 0, 0.633712, -0.773569, 300, 0, 1, '', 0), +(@OGUID+22, 181288, 0, 0, 0, 1, 1, 2279.25, 456.009, 33.867, 0.3665, 0, 0, 0.182226, 0.983257, 120, 0, 1, '', 0), +(@OGUID+23, 181288, 1, 0, 0, 1, 1, -7216.68, -3859.39, 11.4943, -2.72271, 0, 0, -0.978147, 0.207914, 300, 0, 1, '', 0), +(@OGUID+24, 181288, 1, 0, 0, 1, 1, -7122.51, -3657.11, 8.82202, -1.74533, 0, 0, -0.766045, 0.642787, 180, 100, 1, '', 0), +(@OGUID+25, 181288, 1, 0, 0, 1, 1, -7000.75, 918.851, 8.93831, -2.23402, 0, 0, -0.898794, 0.438372, 900, 100, 1, '', 0), +(@OGUID+26, 181288, 1, 0, 0, 1, 1, -6771.96, 527.151, -1.40004, 3.1949, 0, 0, 0.999645, -0.0266505, 300, 0, 1, '', 0), +(@OGUID+27, 181288, 1, 0, 0, 1, 1, -5513.93, -2299.73, -58.0752, 2.44346, 0, 0, 0.939692, 0.342021, 180, 100, 1, '', 0), +(@OGUID+28, 181288, 1, 0, 0, 1, 1, -4573.22, 407.388, 41.5461, 2.46091, 0, 0, 0.942641, 0.333809, 180, 100, 1, '', 0), +(@OGUID+29, 181288, 1, 0, 0, 1, 1, -4412.02, 3480.24, 12.6312, 6.12709, 0, 0, 0.0779684, -0.996956, 300, 0, 1, '', 0), +(@OGUID+30, 181288, 1, 0, 0, 1, 1, -3447.55, -4231.67, 10.6645, 0.802851, 0, 0, 0.390731, 0.920505, 180, 100, 1, '', 0), +(@OGUID+31, 181288, 1, 0, 0, 1, 1, -3110.59, -2722.41, 33.4626, 0.226893, 0, 0, 0.113203, 0.993572, 180, 100, 1, '', 0), +(@OGUID+32, 181288, 1, 0, 0, 1, 1, -2329.42, -624.806, -8.27507, 5.5, 0, 0, 0.381661, -0.924302, 0, 100, 1, '', 0), +(@OGUID+33, 181288, 1, 0, 0, 1, 1, -1862.36, 3055.71, 0.744157, 2.49582, 0, 0, 0.948324, 0.317305, 180, 100, 1, '', 0), +(@OGUID+34, 181288, 1, 0, 0, 1, 1, -273.242, -2662.82, 91.695, -1.8675, 0, 0, -0.803856, 0.594824, 180, 100, 1, '', 0), +(@OGUID+35, 181288, 1, 0, 0, 1, 1, -55.5039, 1271.35, 91.9489, 1.5708, 0, 0, 0.707108, 0.707106, 180, 100, 1, '', 0), +(@OGUID+36, 181288, 1, 0, 0, 1, 1, 145.521, -4713.82, 18.129, -2.53, 0, 0, -0.953607, 0.301053, 120, 0, 1, '', 0), +(@OGUID+37, 181288, 1, 0, 0, 1, 1, 952.992, 776.968, 104.474, -1.55334, 0, 0, -0.700908, 0.713252, 180, 100, 1, '', 0), +(@OGUID+38, 181288, 1, 0, 0, 1, 1, 2014.65, -2337.84, 89.5211, 2.37365, 0, 0, 0.927184, 0.374606, 180, 100, 1, '', 0), +(@OGUID+39, 181288, 1, 0, 0, 1, 1, 2558.73, -481.666, 109.821, -2.47837, 0, 0, -0.945519, 0.325567, 180, 100, 1, '', 0), +(@OGUID+40, 181288, 1, 0, 0, 1, 1, 6327.68, 512.61, 17.4723, 0.034907, 0, 0, 0.0174526, 0.999848, 180, 100, 1, '', 0), +(@OGUID+41, 181288, 1, 0, 0, 1, 1, 6855.99, -4564.4, 708.51, 0.855211, 0, 0, 0.414693, 0.909961, 180, 100, 1, '', 0), +(@OGUID+42, 181288, 1, 0, 0, 1, 1, 6860.03, -4767.11, 696.833, -2.63545, 0, 0, -0.968148, 0.250379, 180, 100, 1, '', 0), +(@OGUID+43, 181288, 1, 0, 0, 1, 1, 9778.64, 1019.38, 1299.79, 0.261799, 0, 0, 0.130526, 0.991445, 180, 100, 1, '', 0), +(@OGUID+44, 181288, 530, 0, 0, 1, 1, -4223.84, -12318.4, 2.47695, 5.69342, 0, 0, 0.290628, -0.956836, 300, 0, 1, '', 0), +(@OGUID+45, 181288, 530, 0, 0, 1, 1, -3941.98, 2048.49, 95.0656, 4.87742, 0, 0, 0.64642, -0.762982, 300, 0, 1, '', 0), +(@OGUID+46, 181288, 530, 0, 0, 1, 1, -3059.17, 2374.85, 63.1011, 2.03334, 0, 0, 0.850361, 0.526201, 300, 0, 1, '', 0), +(@OGUID+47, 181288, 530, 0, 0, 1, 1, -3004.07, 4152.48, 3.64988, 1.75455, 0, 0, 0.769, 0.639249, 300, 0, 1, '', 0), +(@OGUID+48, 181288, 530, 0, 0, 1, 1, -2553.32, 4277.61, 20.614, -1.36136, 0, 0, -0.629322, 0.777145, 180, 100, 1, '', 0), +(@OGUID+49, 181288, 530, 0, 0, 1, 1, -2526.69, 7548.83, -2.23534, 5.32817, 0, 0, 0.459567, -0.888143, 300, 0, 1, '', 0), +(@OGUID+50, 181288, 530, 0, 0, 1, 1, -2254.78, -11896.3, 27.4979, 5.24028, 0, 0, 0.49814, -0.867096, 300, 0, 1, '', 0), +(@OGUID+51, 181288, 530, 0, 0, 1, 1, -1211.01, 7474.44, 21.9953, -2.02458, 0, 0, -0.848048, 0.52992, 180, 100, 1, '', 0), +(@OGUID+52, 181288, 530, 0, 0, 1, 1, -528.509, 2339.11, 38.7252, 2.14675, 0, 0, 0.878816, 0.477161, 180, 100, 1, '', 0), +(@OGUID+53, 181288, 530, 0, 0, 1, 1, 41.2448, 2587.44, 68.3453, -2.28638, 0, 0, -0.909961, 0.414694, 180, 100, 1, '', 0), +(@OGUID+54, 181288, 530, 0, 0, 1, 1, 192.209, 6015.13, 22.1067, 0.00709009, 0, 0, 0.00354504, 0.999994, 300, 0, 1, '', 0), +(@OGUID+55, 181288, 530, 0, 0, 1, 1, 200.9, 7686.96, 22.508, -0.506145, 0, 0, -0.25038, 0.968148, 180, 100, 1, '', 0), +(@OGUID+56, 181288, 530, 0, 0, 1, 1, 2019.7, 6587.14, 134.985, 6.23705, 0, 0, 0.0230656, -0.999734, 300, 0, 1, '', 0), +(@OGUID+57, 181288, 530, 0, 0, 1, 1, 2282.43, 6134.5, 136.337, 6.01364, 0, 0, 0.134365, -0.990932, 300, 0, 1, '', 0), +(@OGUID+58, 181288, 530, 0, 0, 1, 1, 2922.17, 3690.15, 143.809, 5.94709, 0, 0, 0.167258, -0.985913, 300, 0, 1, '', 0), +(@OGUID+59, 181288, 530, 0, 0, 1, 1, 3121.5, 3753.88, 141.851, 5.85856, 0, 0, 0.210721, -0.977546, 300, 0, 1, '', 0), +(@OGUID+60, 181288, 530, 0, 0, 1, 1, 7693.53, -6836.51, 77.787, 2.7052, 0, 0, 0.976289, 0.216469, 120, 0, 1, '', 0), +(@OGUID+61, 181288, 530, 0, 0, 1, 1, 9386.86, -6772.24, 14.412, -2.9146, 0, 0, -0.993566, 0.113253, 120, 0, 1, '', 0), +(@OGUID+62, 181288, 571, 0, 0, 1, 1, 2454.19, -4910.31, 263.893, 1.66082, 0, 0, 0.738208, 0.674573, 300, 0, 1, '', 0), +(@OGUID+63, 181288, 571, 0, 0, 1, 1, 2579.72, -4325.59, 276.934, 5.77529, 0, 0, 0.251227, -0.967928, 300, 0, 1, '', 0), +(@OGUID+64, 181288, 571, 0, 0, 1, 1, 3368.48, -2135.25, 124.53, 0.20224, 0, 0, 0.100948, 0.994892, 300, 0, 1, '', 0), +(@OGUID+65, 181288, 571, 0, 0, 1, 1, 3403.4, -2896.41, 201.988, 2.32303, 0, 0, 0.917407, 0.39795, 300, 0, 1, '', 0), +(@OGUID+66, 181288, 571, 0, 0, 1, 1, 3773.85, 1464.02, 92.4174, 6.10863, 0, 0, 0.0871668, -0.996194, 300, 0, 1, '', 0), +(@OGUID+67, 181288, 571, 0, 0, 1, 1, 3936.15, -583.456, 240.5, 4.0611, 0, 0, 0.896162, -0.443727, 300, 0, 1, '', 0), +(@OGUID+68, 181288, 571, 0, 0, 1, 1, 4122.37, 5390.27, 27.8408, 5.32484, 0, 0, 0.461045, -0.887377, 300, 0, 1, '', 0), +(@OGUID+69, 181288, 571, 0, 0, 1, 1, 4441.05, 5627.71, 56.3487, 4.54665, 0, 0, 0.763211, -0.64615, 300, 0, 1, '', 0), +(@OGUID+70, 181288, 571, 0, 0, 1, 1, 5144.94, -695.736, 171.284, 5.22017, 0, 0, 0.506834, -0.862044, 300, 0, 1, '', 0), +(@OGUID+71, 181288, 571, 0, 0, 1, 1, 5294.92, -2761.88, 292.419, 2.12359, 0, 0, 0.873232, 0.487305, 300, 0, 1, '', 0), +(@OGUID+72, 181288, 571, 0, 0, 1, 1, 5369.18, 4842.41, -197.357, 4.53948, 0, 0, 0.765522, -0.643409, 300, 0, 1, '', 0), +(@OGUID+73, 181288, 571, 0, 0, 1, 1, 5499.12, 4869.82, -197.467, 5.88414, 0, 0, 0.198201, -0.980161, 300, 0, 1, '', 0), +(@OGUID+74, 181288, 571, 0, 0, 1, 1, 5530.53, -726.151, 148.904, 5.3977, 0, 0, 0.428419, -0.90358, 300, 0, 1, '', 0), +(@OGUID+75, 181288, 571, 0, 0, 1, 1, 5626.92, -2622.29, 292.417, 1.6785, 0, 0, 0.744142, 0.668021, 300, 0, 1, '', 0), +(@OGUID+76, 181288, 571, 0, 0, 1, 1, 6081.58, -1107.81, 419.498, 5.2117, 0, 0, 0.51048, -0.85989, 300, 0, 1, '', 0), +(@OGUID+77, 181288, 571, 0, 0, 1, 1, 6142.19, -1020.44, 408.496, 1.91604, 0, 0, 0.818054, 0.575141, 300, 0, 1, '', 0); + +DELETE FROM `game_event_gameobject` WHERE `eventEntry` = 1 AND `guid` BETWEEN @OGUID AND @OGUID+77; +INSERT INTO `game_event_gameobject` (`eventEntry`, `guid`) VALUES +(1, @OGUID+0 ), +(1, @OGUID+1 ), +(1, @OGUID+2 ), +(1, @OGUID+3 ), +(1, @OGUID+4 ), +(1, @OGUID+5 ), +(1, @OGUID+6 ), +(1, @OGUID+7 ), +(1, @OGUID+8 ), +(1, @OGUID+9 ), +(1, @OGUID+10), +(1, @OGUID+11), +(1, @OGUID+12), +(1, @OGUID+13), +(1, @OGUID+14), +(1, @OGUID+15), +(1, @OGUID+16), +(1, @OGUID+17), +(1, @OGUID+18), +(1, @OGUID+19), +(1, @OGUID+20), +(1, @OGUID+21), +(1, @OGUID+22), +(1, @OGUID+23), +(1, @OGUID+24), +(1, @OGUID+25), +(1, @OGUID+26), +(1, @OGUID+27), +(1, @OGUID+28), +(1, @OGUID+29), +(1, @OGUID+30), +(1, @OGUID+31), +(1, @OGUID+32), +(1, @OGUID+33), +(1, @OGUID+34), +(1, @OGUID+35), +(1, @OGUID+36), +(1, @OGUID+37), +(1, @OGUID+38), +(1, @OGUID+39), +(1, @OGUID+40), +(1, @OGUID+41), +(1, @OGUID+42), +(1, @OGUID+43), +(1, @OGUID+44), +(1, @OGUID+45), +(1, @OGUID+46), +(1, @OGUID+47), +(1, @OGUID+48), +(1, @OGUID+49), +(1, @OGUID+50), +(1, @OGUID+51), +(1, @OGUID+52), +(1, @OGUID+53), +(1, @OGUID+54), +(1, @OGUID+55), +(1, @OGUID+56), +(1, @OGUID+57), +(1, @OGUID+58), +(1, @OGUID+59), +(1, @OGUID+60), +(1, @OGUID+61), +(1, @OGUID+62), +(1, @OGUID+63), +(1, @OGUID+64), +(1, @OGUID+65), +(1, @OGUID+66), +(1, @OGUID+67), +(1, @OGUID+68), +(1, @OGUID+69), +(1, @OGUID+70), +(1, @OGUID+71), +(1, @OGUID+72), +(1, @OGUID+73), +(1, @OGUID+74), +(1, @OGUID+75), +(1, @OGUID+76), +(1, @OGUID+77); + +SET @OGUID := 76300; + +DELETE FROM `gameobject` WHERE `id` IN (SELECT `entry` FROM `gameobject_template` WHERE `name` IN ('Horde Bonfire', 'Alliance Bonfire')) /* AND `guid` BETWEEN @OGUID AND @OGUID+77 */; +INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`) VALUES +(@OGUID+0 , 187951, 0, 0, 0, 1, 1, -14376.7, 115.921, 1.4532, 2.11185, 0, 0, 0.870356, 0.492423, 180, 100, 1, '', 0), +(@OGUID+1 , 187944, 0, 0, 0, 1, 1, -14288.1, 61.8062, 0.68836, 1.37881, 0, 0, 0.636078, 0.771625, 180, 100, 1, '', 0), +(@OGUID+2 , 187920, 0, 0, 0, 1, 1, -10951.5, -3218.1, 41.3475, 1.91986, 0, 0, 0.819151, 0.573577, 180, 100, 1, '', 0), +(@OGUID+3 , 187926, 0, 0, 0, 1, 1, -10704.8, -1146.38, 24.7909, 2.09439, 0, 0, 0.866024, 0.500002, 180, 100, 1, '', 0), +(@OGUID+4 , 187564, 0, 0, 0, 1, 1, -10657.1, 1054.63, 32.6733, 2.47837, 0, 0, 0.945519, 0.325567, 180, 100, 1, '', 0), +(@OGUID+5 , 187969, 0, 0, 0, 1, 1, -10331.4, -3297.73, 21.9992, -2.89725, 0, 0, -0.992546, 0.121868, 180, 100, 1, '', 0), +(@OGUID+6 , 187934, 0, 0, 0, 1, 1, -9434.3, -2110.36, 65.8038, 0.349066, 0, 0, 0.173648, 0.984808, 180, 100, 1, '', 0), +(@OGUID+7 , 187928, 0, 0, 0, 1, 1, -9394.21, 37.5017, 59.882, 1.15192, 0, 0, 0.54464, 0.83867, 180, 100, 1, '', 0), +(@OGUID+8 , 187922, 0, 0, 0, 1, 1, -8245.62, -2623.9, 133.155, 4.04776, 0, 0, 0.899102, -0.43774, 300, 0, 1, '', 0), +(@OGUID+9 , 187956, 0, 0, 0, 1, 1, -7596.42, -2086.6, 125.17, -0.942478, 0, 0, -0.453991, 0.891006, 180, 100, 1, '', 0), +(@OGUID+10, 187954, 0, 0, 0, 1, 1, -6704.48, -2200.91, 248.609, 0.017453, 0, 0, 0.00872639, 0.999962, 180, 100, 1, '', 0), +(@OGUID+11, 187925, 0, 0, 0, 1, 1, -5404.93, -492.299, 395.597, -0.506145, 0, 0, -0.25038, 0.968148, 180, 100, 1, '', 0), +(@OGUID+12, 187932, 0, 0, 0, 1, 1, -5233.16, -2893.37, 337.286, -0.226893, 0, 0, -0.113203, 0.993572, 180, 100, 1, '', 0), +(@OGUID+13, 187940, 0, 0, 0, 1, 1, -3448.2, -938.102, 10.6583, 0.034907, 0, 0, 0.0174526, 0.999848, 180, 100, 1, '', 0), +(@OGUID+14, 187914, 0, 0, 0, 1, 1, -1211.6, -2676.88, 45.3612, -0.645772, 0, 0, -0.317305, 0.948324, 180, 100, 1, '', 0), +(@OGUID+15, 187947, 0, 0, 0, 1, 1, -1134.84, -3531.81, 51.0719, -0.820305, 0, 0, -0.398749, 0.91706, 180, 100, 1, '', 0), +(@OGUID+16, 187931, 0, 0, 0, 1, 1, -604.148, -545.813, 36.579, 0.698132, 0, 0, 0.34202, 0.939693, 180, 100, 1, '', 0), +(@OGUID+17, 187972, 0, 0, 0, 1, 1, -447.95, -4527.65, 8.59595, 1.53589, 0, 0, 0.694658, 0.71934, 180, 100, 1, '', 0), +(@OGUID+18, 187964, 0, 0, 0, 1, 1, -134.688, -802.767, 55.0147, -1.62316, 0, 0, -0.725376, 0.688353, 180, 100, 1, '', 0), +(@OGUID+19, 187938, 0, 0, 0, 1, 1, 188.243, -2132.53, 102.674, -1.37881, 0, 0, -0.636078, 0.771625, 180, 100, 1, '', 0), +(@OGUID+20, 187559, 0, 0, 0, 1, 1, 587.056, 1365.02, 90.4778, 2.6529, 0, 0, 0.970296, 0.241922, 180, 100, 1, '', 0), +(@OGUID+21, 187939, 0, 0, 0, 1, 1, 989.562, -1453.47, 61.0011, 4.9105, 0, 0, 0.633712, -0.773569, 120, 255, 1, '', 0), +(@OGUID+22, 187974, 0, 0, 0, 1, 1, 2279.25, 456.009, 33.867, 0.3665, 0, 0, 0.182226, 0.983257, 120, 0, 1, '', 0), +(@OGUID+23, 187945, 1, 0, 0, 1, 1, -7216.68, -3859.39, 11.4943, -2.72271, 0, 0, -0.978147, 0.207914, 180, 100, 1, '', 0), +(@OGUID+24, 187952, 1, 0, 0, 1, 1, -7122.51, -3657.11, 8.82202, -1.74533, 0, 0, -0.766045, 0.642787, 180, 100, 1, '', 0), +(@OGUID+25, 187950, 1, 0, 0, 1, 1, -7000.75, 918.851, 8.93831, -2.23402, 0, 0, -0.898794, 0.438372, 180, 100, 1, '', 0), +(@OGUID+26, 187943, 1, 0, 0, 1, 1, -6771.96, 527.151, -1.40004, 3.1949, 0, 0, 0.999645, -0.0266505, 300, 0, 1, '', 0), +(@OGUID+27, 187973, 1, 0, 0, 1, 1, -5513.93, -2299.73, -58.0752, 2.44346, 0, 0, 0.939692, 0.342021, 180, 100, 1, '', 0), +(@OGUID+28, 187961, 1, 0, 0, 1, 1, -4573.22, 407.388, 41.5461, 2.46091, 0, 0, 0.942641, 0.333809, 180, 100, 1, '', 0), +(@OGUID+29, 187929, 1, 0, 0, 1, 1, -4412.02, 3480.24, 12.6312, 6.12709, 0, 0, 0.0779684, -0.996956, 300, 0, 1, '', 0), +(@OGUID+30, 187927, 1, 0, 0, 1, 1, -3447.55, -4231.67, 10.6645, 0.802851, 0, 0, 0.390731, 0.920505, 180, 100, 1, '', 0), +(@OGUID+31, 187959, 1, 0, 0, 1, 1, -3110.59, -2722.41, 33.4626, 0.226893, 0, 0, 0.113203, 0.993572, 180, 100, 1, '', 0), +(@OGUID+32, 187965, 1, 0, 0, 1, 1, -2329.42, -624.806, -8.27507, 5.5, 0, 0, 0.381661, -0.924302, 0, 100, 1, '', 0), +(@OGUID+33, 187957, 1, 0, 0, 1, 1, -1862.36, 3055.71, 0.744157, 2.49582, 0, 0, 0.948324, 0.317305, 180, 100, 1, '', 0), +(@OGUID+34, 187971, 1, 0, 0, 1, 1, -273.242, -2662.82, 91.695, -1.8675, 0, 0, -0.803856, 0.594824, 180, 100, 1, '', 0), +(@OGUID+35, 187924, 1, 0, 0, 1, 1, -55.5039, 1271.35, 91.9489, 1.5708, 0, 0, 0.707108, 0.707106, 180, 100, 1, '', 0), +(@OGUID+36, 187958, 1, 0, 0, 1, 1, 145.521, -4713.82, 18.129, -2.53, 0, 0, -0.953607, 0.301053, 120, 0, 1, '', 0), +(@OGUID+37, 187968, 1, 0, 0, 1, 1, 952.992, 776.968, 104.474, -1.55334, 0, 0, -0.700908, 0.713252, 180, 100, 1, '', 0), +(@OGUID+38, 187948, 1, 0, 0, 1, 1, 2014.65, -2337.84, 89.5211, 2.37365, 0, 0, 0.927184, 0.374606, 180, 100, 1, '', 0), +(@OGUID+39, 187916, 1, 0, 0, 1, 1, 2558.73, -481.666, 109.821, -2.47837, 0, 0, -0.945519, 0.325567, 180, 100, 1, '', 0), +(@OGUID+40, 187923, 1, 0, 0, 1, 1, 6327.68, 512.61, 17.4723, 0.034907, 0, 0, 0.0174526, 0.999848, 180, 100, 1, '', 0), +(@OGUID+41, 187953, 1, 0, 0, 1, 1, 6855.99, -4564.4, 708.51, 0.855211, 0, 0, 0.414693, 0.909961, 180, 100, 1, '', 0), +(@OGUID+42, 187946, 1, 0, 0, 1, 1, 6860.03, -4767.11, 696.833, -2.63545, 0, 0, -0.968148, 0.250379, 180, 100, 1, '', 0), +(@OGUID+43, 187936, 1, 0, 0, 1, 1, 9778.64, 1019.38, 1299.79, 0.261799, 0, 0, 0.130526, 0.991445, 180, 100, 1, '', 0), +(@OGUID+44, 187917, 530, 0, 0, 1, 1, -4223.84, -12318.4, 2.47695, 2.93214, 0, 0, 0.994521, 0.104535, 120, 255, 1, '', 0), +(@OGUID+45, 187935, 530, 0, 0, 1, 1, -3941.98, 2048.49, 95.0656, 4.87742, 0, 0, 0.64642, -0.762982, 300, 0, 1, '', 0), +(@OGUID+46, 187967, 530, 0, 0, 1, 1, -3059.17, 2374.85, 63.1011, 2.03334, 0, 0, 0.850361, 0.526201, 300, 0, 1, '', 0), +(@OGUID+47, 187937, 530, 0, 0, 1, 1, -3004.07, 4152.48, 3.64988, 1.75455, 0, 0, 0.769, 0.639249, 300, 0, 1, '', 0), +(@OGUID+48, 187970, 530, 0, 0, 1, 1, -2553.32, 4277.61, 20.614, -1.36136, 0, 0, -0.629322, 0.777145, 180, 100, 1, '', 0), +(@OGUID+49, 187933, 530, 0, 0, 1, 1, -2526.69, 7548.83, -2.23534, 5.32817, 0, 0, 0.459567, -0.888143, 300, 0, 1, '', 0), +(@OGUID+50, 187921, 530, 0, 0, 1, 1, -2254.78, -11896.3, 27.4979, 5.24028, 0, 0, 0.49814, -0.867096, 300, 0, 1, '', 0), +(@OGUID+51, 187966, 530, 0, 0, 1, 1, -1211.01, 7474.44, 21.9953, -2.02458, 0, 0, -0.848048, 0.52992, 180, 100, 1, '', 0), +(@OGUID+52, 187930, 530, 0, 0, 1, 1, -528.509, 2339.11, 38.7252, 2.14675, 0, 0, 0.878816, 0.477161, 180, 100, 1, '', 0), +(@OGUID+53, 187963, 530, 0, 0, 1, 1, 41.2448, 2587.44, 68.3453, -2.28638, 0, 0, -0.909961, 0.414694, 180, 100, 1, '', 0), +(@OGUID+54, 187941, 530, 0, 0, 1, 1, 192.209, 6015.13, 22.1067, 0.00709009, 0, 0, 0.00354504, 0.999994, 300, 0, 1, '', 0), +(@OGUID+55, 187975, 530, 0, 0, 1, 1, 200.9, 7686.96, 22.508, -0.506145, 0, 0, -0.25038, 0.968148, 180, 100, 1, '', 0), +(@OGUID+56, 187919, 530, 0, 0, 1, 1, 2019.7, 6587.14, 134.985, 6.23705, 0, 0, 0.0230656, -0.999734, 120, 255, 1, '', 0), +(@OGUID+57, 187955, 530, 0, 0, 1, 1, 2282.43, 6134.5, 136.337, 6.01364, 0, 0, 0.134365, -0.990932, 300, 0, 1, '', 0), +(@OGUID+58, 187949, 530, 0, 0, 1, 1, 2922.17, 3690.15, 143.809, 5.94709, 0, 0, 0.167258, -0.985913, 300, 0, 1, '', 0), +(@OGUID+59, 187942, 530, 0, 0, 1, 1, 3121.5, 3753.88, 141.851, 5.85856, 0, 0, 0.210721, -0.977546, 300, 0, 1, '', 0), +(@OGUID+60, 187962, 530, 0, 0, 1, 1, 7693.53, -6836.51, 77.787, 2.7052, 0, 0, 0.976289, 0.216469, 120, 0, 1, '', 0), +(@OGUID+61, 187960, 530, 0, 0, 1, 1, 9386.86, -6772.24, 14.412, -2.9146, 0, 0, -0.993566, 0.113253, 120, 0, 1, '', 0), +(@OGUID+62, 194038, 571, 0, 0, 1, 1, 2454.19, -4910.31, 263.893, 1.66082, 0, 0, 0.738208, 0.674573, 300, 0, 1, '', 0), +(@OGUID+63, 194039, 571, 0, 0, 1, 1, 2579.72, -4325.59, 276.934, 5.77529, 0, 0, 0.251227, -0.967928, 300, 0, 1, '', 0), +(@OGUID+64, 194042, 571, 0, 0, 1, 1, 3368.48, -2135.25, 124.53, 0.20224, 0, 0, 0.100948, 0.994892, 300, 0, 1, '', 0), +(@OGUID+65, 194040, 571, 0, 0, 1, 1, 3403.4, -2896.41, 201.988, 2.32303, 0, 0, 0.917407, 0.39795, 300, 0, 1, '', 0), +(@OGUID+66, 194037, 571, 0, 0, 1, 1, 3773.85, 1464.02, 92.4174, 6.10863, 0, 0, 0.0871668, -0.996194, 300, 0, 1, '', 0), +(@OGUID+67, 194036, 571, 0, 0, 1, 1, 3936.15, -583.456, 240.5, 4.0611, 0, 0, 0.896162, -0.443727, 300, 0, 1, '', 0), +(@OGUID+68, 194032, 571, 0, 0, 1, 1, 4122.37, 5390.27, 27.8408, 5.32484, 0, 0, 0.461045, -0.887377, 300, 0, 1, '', 0), +(@OGUID+69, 194033, 571, 0, 0, 1, 1, 4441.05, 5627.71, 56.3487, 4.54665, 0, 0, 0.763211, -0.64615, 300, 0, 1, '', 0), +(@OGUID+70, 194045, 571, 0, 0, 1, 1, 5144.94, -695.736, 171.284, 5.22017, 0, 0, 0.506834, -0.862044, 300, 0, 1, '', 0), +(@OGUID+71, 194048, 571, 0, 0, 1, 1, 5294.92, -2761.88, 292.419, 2.12359, 0, 0, 0.873232, 0.487305, 300, 0, 1, '', 0), +(@OGUID+72, 194035, 571, 0, 0, 1, 1, 5369.18, 4842.41, -197.357, 4.53948, 0, 0, 0.765522, -0.643409, 300, 0, 1, '', 0), +(@OGUID+73, 194034, 571, 0, 0, 1, 1, 5499.12, 4869.82, -197.467, 5.88414, 0, 0, 0.198201, -0.980161, 300, 0, 1, '', 0), +(@OGUID+74, 194046, 571, 0, 0, 1, 1, 5530.53, -726.151, 148.904, 5.3977, 0, 0, 0.428419, -0.90358, 300, 0, 1, '', 0), +(@OGUID+75, 194049, 571, 0, 0, 1, 1, 5626.92, -2622.29, 292.417, 1.6785, 0, 0, 0.744142, 0.668021, 300, 0, 1, '', 0), +(@OGUID+76, 194044, 571, 0, 0, 1, 1, 6081.58, -1107.81, 419.498, 5.2117, 0, 0, 0.51048, -0.85989, 300, 0, 1, '', 0), +(@OGUID+77, 194043, 571, 0, 0, 1, 1, 6142.19, -1020.44, 408.496, 1.91604, 0, 0, 0.818054, 0.575141, 300, 0, 1, '', 0); + +DELETE FROM `game_event_gameobject` WHERE `eventEntry` = 1 AND `guid` BETWEEN @OGUID AND @OGUID+77; +INSERT INTO `game_event_gameobject` (`eventEntry`, `guid`) VALUES +(1, @OGUID+0 ), +(1, @OGUID+1 ), +(1, @OGUID+2 ), +(1, @OGUID+3 ), +(1, @OGUID+4 ), +(1, @OGUID+5 ), +(1, @OGUID+6 ), +(1, @OGUID+7 ), +(1, @OGUID+8 ), +(1, @OGUID+9 ), +(1, @OGUID+10), +(1, @OGUID+11), +(1, @OGUID+12), +(1, @OGUID+13), +(1, @OGUID+14), +(1, @OGUID+15), +(1, @OGUID+16), +(1, @OGUID+17), +(1, @OGUID+18), +(1, @OGUID+19), +(1, @OGUID+20), +(1, @OGUID+21), +(1, @OGUID+22), +(1, @OGUID+23), +(1, @OGUID+24), +(1, @OGUID+25), +(1, @OGUID+26), +(1, @OGUID+27), +(1, @OGUID+28), +(1, @OGUID+29), +(1, @OGUID+30), +(1, @OGUID+31), +(1, @OGUID+32), +(1, @OGUID+33), +(1, @OGUID+34), +(1, @OGUID+35), +(1, @OGUID+36), +(1, @OGUID+37), +(1, @OGUID+38), +(1, @OGUID+39), +(1, @OGUID+40), +(1, @OGUID+41), +(1, @OGUID+42), +(1, @OGUID+43), +(1, @OGUID+44), +(1, @OGUID+45), +(1, @OGUID+46), +(1, @OGUID+47), +(1, @OGUID+48), +(1, @OGUID+49), +(1, @OGUID+50), +(1, @OGUID+51), +(1, @OGUID+52), +(1, @OGUID+53), +(1, @OGUID+54), +(1, @OGUID+55), +(1, @OGUID+56), +(1, @OGUID+57), +(1, @OGUID+58), +(1, @OGUID+59), +(1, @OGUID+60), +(1, @OGUID+61), +(1, @OGUID+62), +(1, @OGUID+63), +(1, @OGUID+64), +(1, @OGUID+65), +(1, @OGUID+66), +(1, @OGUID+67), +(1, @OGUID+68), +(1, @OGUID+69), +(1, @OGUID+70), +(1, @OGUID+71), +(1, @OGUID+72), +(1, @OGUID+73), +(1, @OGUID+74), +(1, @OGUID+75), +(1, @OGUID+76), +(1, @OGUID+77); + +DELETE FROM `game_event_gameobject` WHERE `eventEntry` = 1 AND `guid` BETWEEN 242500 AND 242577; diff --git a/data/sql/updates/db_world/2023_06_27_00.sql b/data/sql/updates/db_world/2023_06_27_00.sql new file mode 100644 index 000000000..cb27e77da --- /dev/null +++ b/data/sql/updates/db_world/2023_06_27_00.sql @@ -0,0 +1,4 @@ +-- DB update 2023_06_26_01 -> 2023_06_27_00 +-- 31994 - Shoulder Charge +DELETE FROM `spell_custom_attr` WHERE `spell_id` = 31994; +INSERT INTO `spell_custom_attr` (`spell_id`, `attributes`) VALUES (31994, 16384); diff --git a/data/sql/updates/db_world/2023_06_29_00.sql b/data/sql/updates/db_world/2023_06_29_00.sql new file mode 100644 index 000000000..91c27f086 --- /dev/null +++ b/data/sql/updates/db_world/2023_06_29_00.sql @@ -0,0 +1,4 @@ +-- DB update 2023_06_27_00 -> 2023_06_29_00 +DELETE FROM `quest_offer_reward_locale` WHERE `ID`=1045 AND `locale`='ruRU'; +INSERT INTO `quest_offer_reward_locale` (`ID`, `locale`, `RewardText`, `VerifiedBuild`) VALUES +(1045, 'ruRU', 'Славная работа, $N. Спасибо тебе.', 18019); diff --git a/data/sql/updates/db_world/2023_06_29_01.sql b/data/sql/updates/db_world/2023_06_29_01.sql new file mode 100644 index 000000000..0a667eff4 --- /dev/null +++ b/data/sql/updates/db_world/2023_06_29_01.sql @@ -0,0 +1,4 @@ +-- DB update 2023_06_29_00 -> 2023_06_29_01 +-- +UPDATE `creature_template` SET `flags_extra` = `flags_extra`|128 WHERE `entry`=22021; + diff --git a/data/sql/updates/db_world/2023_06_29_02.sql b/data/sql/updates/db_world/2023_06_29_02.sql new file mode 100644 index 000000000..fdcdfd2a3 --- /dev/null +++ b/data/sql/updates/db_world/2023_06_29_02.sql @@ -0,0 +1,23 @@ +-- DB update 2023_06_29_01 -> 2023_06_29_02 +-- Fix SAI Yenniku -- +DELETE FROM `creature_text` WHERE (`CreatureID` = 2530 AND `GroupID` = 0); +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(2530, 0, 0, '%s is struck dumb by the Soul Gem!', 16, 0, 100, 0, 0, 0, 681, 0, 'Yenniku'); + +UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE (`entry` = 2530); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 2530); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2530, 0, 0, 1, 8, 0, 100, 0, 3607, 0, 30000, 30000, 0, 2, 35, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Yenniku - On Spellhit \'Yenniku`s Release\' - Set Faction 35'), +(2530, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 80, 253000, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Yenniku - On Spellhit \'Yenniku`s Release\' - Run Script'), +(2530, 0, 2, 0, 20, 0, 100, 0, 593, 0, 0, 0, 0, 80, 253001, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Yenniku - On Quest \'Filling the Soul Gem\' Finished - Run Script'); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` IN (253000, 253001)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(253000, 9, 0, 0, 0, 0, 100, 0, 100, 100, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 18, 6, 0, 0, 0, 0, 0, 0, 0, 'Yenniku - Actionlist - Set Orientation Closest Player'), +(253000, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Yenniku - Actionlist - Say Line 0'), +(253000, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 75, 18970, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Yenniku - Actionlist - Add Aura \'Self Stun - (Visual only)\''), +(253000, 9, 3, 0, 0, 0, 100, 0, 60000, 60000, 0, 0, 0, 28, 18970, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Yenniku - Actionlist - Remove Aura \'Self Stun - (Visual only)\''), +(253000, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 2, 28, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Yenniku - Actionlist - Set Faction 28'), +(253001, 9, 5, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 2, 28, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Yenniku - Actionlist - Set Faction 28'), +(253001, 9, 6, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 28, 18970, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Yenniku - Actionlist - Remove Aura \'Self Stun - (Visual only)\''); diff --git a/data/sql/updates/db_world/2023_06_30_00.sql b/data/sql/updates/db_world/2023_06_30_00.sql new file mode 100644 index 000000000..5fa283da6 --- /dev/null +++ b/data/sql/updates/db_world/2023_06_30_00.sql @@ -0,0 +1,12 @@ +-- DB update 2023_06_29_02 -> 2023_06_30_00 +-- +UPDATE `creature_loot_template` SET `Chance` = 0, `GroupId` = 1 WHERE (`Entry` = 20303); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 18478); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(18478, 0, 0, 0, 0, 0, 100, 0, 8500, 16800, 10900, 24100, 0, 11, 16856, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Avatar of the Martyred - In Combat - Cast \'Mortal Strike\''), +(18478, 0, 1, 0, 0, 0, 100, 0, 6500, 11500, 6200, 15700, 0, 11, 16145, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Avatar of the Martyred - In Combat - Cast \'Sunder Armor\''), +(18478, 0, 2, 0, 1, 0, 100, 512, 30000, 30000, 30000, 30000, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Avatar of the Martyred - Out of Combat - Despawn After 30s'), +(18478, 0, 3, 4, 54, 0, 100, 0, 0, 0, 0, 0, 0, 11, 33422, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Avatar of the Martyred - On Just Summoned - Cast \'Phase In\''), +(18478, 0, 4, 5, 61, 0, 100, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Avatar of the Martyred - On Just Summoned - Set In Combat With Zone'), +(18478, 0, 5, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 116, 900, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Avatar of the Martyred - On Just Summoned - Set Corpse Delay to 15 Minutes'); diff --git a/data/sql/updates/db_world/2023_07_02_00.sql b/data/sql/updates/db_world/2023_07_02_00.sql new file mode 100644 index 000000000..50af79ad6 --- /dev/null +++ b/data/sql/updates/db_world/2023_07_02_00.sql @@ -0,0 +1,4 @@ +-- DB update 2023_06_30_00 -> 2023_07_02_00 +-- +UPDATE `smart_scripts` SET `event_param5`=5000 WHERE `entryorguid` = 16420 AND `source_type` = 0 AND `id`=0; +UPDATE `smart_scripts` SET `event_param5`=1000 WHERE `entryorguid` = 30085 AND `source_type` = 0 AND `id` = 1; diff --git a/src/server/apps/worldserver/Main.cpp b/src/server/apps/worldserver/Main.cpp index 436724ff8..8483737e2 100644 --- a/src/server/apps/worldserver/Main.cpp +++ b/src/server/apps/worldserver/Main.cpp @@ -113,7 +113,6 @@ bool LoadRealmInfo(Acore::Asio::IoContext& ioContext); AsyncAcceptor* StartRaSocketAcceptor(Acore::Asio::IoContext& ioContext); void ShutdownCLIThread(std::thread* cliThread); void AuctionListingRunnable(); -void ShutdownAuctionListingThread(std::thread* thread); void WorldUpdateLoop(); variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, [[maybe_unused]] std::string& cfg_service); @@ -399,9 +398,9 @@ int main(int argc, char** argv) cliThread.reset(new std::thread(CliThread), &ShutdownCLIThread); } - // Launch CliRunnable thread - std::shared_ptr auctionLisingThread; - auctionLisingThread.reset(new std::thread(AuctionListingRunnable), + // Launch auction listing thread + std::shared_ptr auctionListingThread; + auctionListingThread.reset(new std::thread(AuctionListingRunnable), [](std::thread* thr) { thr->join(); @@ -729,42 +728,41 @@ void AuctionListingRunnable() while (!World::IsStopped()) { - if (AsyncAuctionListingMgr::IsAuctionListingAllowed()) + Milliseconds diff = AsyncAuctionListingMgr::GetDiff(); + AsyncAuctionListingMgr::ResetDiff(); + + if (!AsyncAuctionListingMgr::GetTempList().empty() || !AsyncAuctionListingMgr::GetList().empty()) { - uint32 diff = AsyncAuctionListingMgr::GetDiff(); - AsyncAuctionListingMgr::ResetDiff(); - - if (AsyncAuctionListingMgr::GetTempList().size() || AsyncAuctionListingMgr::GetList().size()) { - std::lock_guard guard(AsyncAuctionListingMgr::GetLock()); + std::lock_guard guard(AsyncAuctionListingMgr::GetTempLock()); + for (auto const& delayEvent: AsyncAuctionListingMgr::GetTempList()) + AsyncAuctionListingMgr::GetList().emplace_back(delayEvent); + + AsyncAuctionListingMgr::GetTempList().clear(); + } + + for (auto& itr: AsyncAuctionListingMgr::GetList()) + { + if (itr._pickupTimer <= diff) { - std::lock_guard guard(AsyncAuctionListingMgr::GetTempLock()); - - for (auto const& delayEvent : AsyncAuctionListingMgr::GetTempList()) - AsyncAuctionListingMgr::GetList().emplace_back(delayEvent); - - AsyncAuctionListingMgr::GetTempList().clear(); + itr._pickupTimer = Milliseconds::zero(); } - - for (auto& itr : AsyncAuctionListingMgr::GetList()) + else { - if (itr._msTimer <= diff) - itr._msTimer = 0; - else - itr._msTimer -= diff; + itr._pickupTimer -= diff; } + } - for (std::list::iterator itr = AsyncAuctionListingMgr::GetList().begin(); itr != AsyncAuctionListingMgr::GetList().end(); ++itr) - { - if ((*itr)._msTimer != 0) - continue; + for (auto itr = AsyncAuctionListingMgr::GetList().begin(); itr != AsyncAuctionListingMgr::GetList().end(); ++itr) + { + if ((*itr)._pickupTimer != Milliseconds::zero()) + continue; - if ((*itr).Execute()) - AsyncAuctionListingMgr::GetList().erase(itr); + if ((*itr).Execute()) + AsyncAuctionListingMgr::GetList().erase(itr); - break; - } + break; } } std::this_thread::sleep_for(1ms); @@ -773,15 +771,6 @@ void AuctionListingRunnable() LOG_INFO("server", "Auction House Listing thread exiting without problems."); } -void ShutdownAuctionListingThread(std::thread* thread) -{ - if (thread) - { - thread->join(); - delete thread; - } -} - variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, [[maybe_unused]] std::string& configService) { options_description all("Allowed options"); @@ -791,7 +780,7 @@ variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, [ ("dry-run,d", "Dry run") ("config,c", value(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_CORE_CONFIG))), "use as configuration file"); -#if AC_PLATFORM == WARHEAD_PLATFORM_WINDOWS +#if AC_PLATFORM == AC_PLATFORM_WINDOWS options_description win("Windows platform specific options"); win.add_options() ("service,s", value(&configService)->default_value(""), "Windows service options: [install | uninstall]"); diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist index df90051a6..be7c50cf7 100644 --- a/src/server/apps/worldserver/worldserver.conf.dist +++ b/src/server/apps/worldserver/worldserver.conf.dist @@ -3843,6 +3843,13 @@ ChangeFaction.MaxMoney = 0 Pet.RankMod.Health = 1 +# +# AuctionHouse.SearchTimeout +# Description: Time (in milliseconds) after which an auction house search is discarded. +# Default: 1000 - (1 second) + +AuctionHouse.SearchTimeout = 1000 + # ################################################################################################### diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 7c9e29100..53f46cfcd 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -988,7 +988,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (!IsSmart()) break; - if (targets.empty()) + if (e.target.type == SMART_TARGET_NONE || e.target.type == SMART_TARGET_SELF) { CAST_AI(SmartAI, me->AI())->StopFollow(false); break; @@ -1644,6 +1644,15 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u break; } + if (e.action.orientation.turnAngle) + { + float turnOri = me->GetOrientation() + (static_cast(e.action.orientation.turnAngle) * M_PI / 180.0f); + me->SetFacingTo(turnOri); + if (e.action.orientation.quickChange) + me->SetOrientation(turnOri); + break; + } + if (e.GetTargetType() == SMART_TARGET_SELF) { me->SetFacingTo((me->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && me->GetTransGUID() ? me->GetTransportHomePosition() : me->GetHomePosition()).GetOrientation()); @@ -2824,6 +2833,48 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } break; } + case SMART_ACTION_SET_SCALE: + { + float scale = static_cast(e.action.setScale.scale) / 100.0f; + + for (WorldObject* target : targets) + { + if (IsUnit(target)) + { + target->ToUnit()->SetObjectScale(scale); + } + } + break; + } + case SMART_ACTION_SUMMON_RADIAL: + { + if (!me) + break; + + TempSummonType spawnType = (e.action.radialSummon.summonDuration > 0) ? TEMPSUMMON_TIMED_DESPAWN : TEMPSUMMON_CORPSE_DESPAWN; + + float startAngle = me->GetOrientation() + (static_cast(e.action.radialSummon.startAngle) * M_PI / 180.0f); + float stepAngle = static_cast(e.action.radialSummon.stepAngle) * M_PI / 180.0f; + + if (e.action.radialSummon.dist) + { + for (uint32 itr = 0; itr < e.action.radialSummon.repetitions; itr++) + { + Position summonPos = me->GetPosition(); + summonPos.RelocatePolarOffset(itr * stepAngle, static_cast(e.action.radialSummon.dist)); + me->SummonCreature(e.action.radialSummon.summonEntry, summonPos, spawnType, e.action.radialSummon.summonDuration); + } + break; + } + + for (uint32 itr = 0; itr < e.action.radialSummon.repetitions; itr++) + { + float currentAngle = startAngle + (itr * stepAngle); + me->SummonCreature(e.action.radialSummon.summonEntry, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), currentAngle, spawnType, e.action.radialSummon.summonDuration); + } + + break; + } default: LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); break; @@ -4157,34 +4208,105 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui break; case SMART_EVENT_NEAR_PLAYERS: { - ObjectVector units; - GetWorldObjectsInDist(units, static_cast(e.event.nearPlayer.radius)); + uint32 playerCount = 0; + ObjectVector targets; + GetWorldObjectsInDist(targets, static_cast(e.event.nearPlayer.radius)); - if (!units.empty()) + if (!targets.empty()) { - if (!unit || unit->GetTypeId() != TYPEID_PLAYER) - return; + for (WorldObject* target : targets) + { + if (IsPlayer(target)) + playerCount++; - if (units.size() >= e.event.nearPlayer.minCount) - ProcessAction(e, unit); + if (playerCount >= e.event.nearPlayer.minCount) + ProcessAction(e, target->ToUnit()); + } } - RecalcTimer(e, e.event.nearPlayer.checkTimer, e.event.nearPlayer.checkTimer); + RecalcTimer(e, e.event.nearPlayer.repeatMin, e.event.nearPlayer.repeatMax); break; } case SMART_EVENT_NEAR_PLAYERS_NEGATION: { - ObjectVector units; - GetWorldObjectsInDist(units, static_cast(e.event.nearPlayerNegation.radius)); + uint32 playerCount = 0; + ObjectVector targets; + GetWorldObjectsInDist(targets, static_cast(e.event.nearPlayerNegation.radius)); - if (!units.empty()) + if (!targets.empty()) { - if (!unit || unit->GetTypeId() != TYPEID_PLAYER) - return; + for (WorldObject* target : targets) + { + if (IsPlayer(target)) + playerCount++; + } - if (units.size() < e.event.nearPlayerNegation.minCount) + if (playerCount <= e.event.nearPlayerNegation.maxCount) ProcessAction(e, unit); } - RecalcTimer(e, e.event.nearPlayerNegation.checkTimer, e.event.nearPlayerNegation.checkTimer); + RecalcTimer(e, e.event.nearPlayerNegation.repeatMin, e.event.nearPlayerNegation.repeatMax); + break; + } + case SMART_EVENT_NEAR_UNIT: + { + uint32 unitCount = 0; + ObjectVector targets; + GetWorldObjectsInDist(targets, static_cast(e.event.nearUnit.range)); + + if (!targets.empty()) + { + if (e.event.nearUnit.type) + { + for (WorldObject* target : targets) + { + if (IsGameObject(target) && target->GetEntry() == e.event.nearUnit.entry) + unitCount++; + } + } + else + { + for (WorldObject* target : targets) + { + if (IsCreature(target) && target->GetEntry() == e.event.nearUnit.entry) + unitCount++; + } + } + + if (unitCount >= e.event.nearUnit.count) + ProcessAction(e, unit); + } + RecalcTimer(e, e.event.nearUnit.timer, e.event.nearUnit.timer); + break; + } + case SMART_EVENT_AREA_CASTING: + { + if (!me || !me->IsEngaged()) + return; + + float range = static_cast(e.event.areaCasting.range); + ThreatContainer::StorageType threatList = me->GetThreatMgr().GetThreatList(); + for (ThreatContainer::StorageType::const_iterator i = threatList.begin(); i != threatList.end(); ++i) + { + if (Unit* target = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid())) + { + if (e.event.areaCasting.range && !me->IsWithinDistInMap(target, range)) + continue; + + if (!target || !target->IsNonMeleeSpellCast(false, false, true)) + continue; + + if (e.event.areaCasting.spellId > 0) + if (Spell* currSpell = target->GetCurrentSpell(CURRENT_GENERIC_SPELL)) + if (currSpell->m_spellInfo->Id != e.event.areaCasting.spellId) + continue; + + ProcessAction(e, target); + RecalcTimer(e, e.event.areaCasting.repeatMin, e.event.areaCasting.repeatMin); + return; + } + } + + // If no targets are found and it's off cooldown, check again + RecalcTimer(e, e.event.areaCasting.checkTimer, e.event.areaCasting.checkTimer); break; } default: @@ -4223,6 +4345,12 @@ void SmartScript::InitTimer(SmartScriptHolder& e) case SMART_EVENT_DISTANCE_GAMEOBJECT: RecalcTimer(e, e.event.distance.repeat, e.event.distance.repeat); break; + case SMART_EVENT_NEAR_UNIT: + RecalcTimer(e, e.event.nearUnit.timer, e.event.nearUnit.timer); + break; + case SMART_EVENT_AREA_CASTING: + RecalcTimer(e, e.event.areaCasting.repeatMin, e.event.areaCasting.repeatMax); + break; default: e.active = true; break; @@ -4276,6 +4404,7 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff) { case SMART_EVENT_NEAR_PLAYERS: case SMART_EVENT_NEAR_PLAYERS_NEGATION: + case SMART_EVENT_NEAR_UNIT: case SMART_EVENT_UPDATE: case SMART_EVENT_UPDATE_OOC: case SMART_EVENT_UPDATE_IC: @@ -4285,6 +4414,7 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff) case SMART_EVENT_TARGET_MANA_PCT: case SMART_EVENT_RANGE: case SMART_EVENT_VICTIM_CASTING: + case SMART_EVENT_AREA_CASTING: case SMART_EVENT_FRIENDLY_HEALTH: case SMART_EVENT_FRIENDLY_IS_CC: case SMART_EVENT_FRIENDLY_MISSING_BUFF: diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 701ff7f40..f0bba12a9 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -280,6 +280,10 @@ void SmartAIMgr::LoadSmartAIFromDB() if (temp.event.minMaxRepeat.min == 0 && temp.event.minMaxRepeat.max == 0) temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE; break; + case SMART_EVENT_AREA_CASTING: + if (temp.event.areaCasting.repeatMin == 0 && temp.event.areaCasting.repeatMax == 0) + temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE; + break; case SMART_EVENT_FRIENDLY_IS_CC: if (temp.event.friendlyCC.repeatMin == 0 && temp.event.friendlyCC.repeatMax == 0) temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE; @@ -346,10 +350,12 @@ void SmartAIMgr::LoadSmartAIFromDB() case SMART_EVENT_TARGET_MANA_PCT: case SMART_EVENT_RANGE: case SMART_EVENT_VICTIM_CASTING: + case SMART_EVENT_AREA_CASTING: case SMART_EVENT_TARGET_BUFFED: case SMART_EVENT_IS_BEHIND_TARGET: case SMART_EVENT_INSTANCE_PLAYER_ENTER: case SMART_EVENT_TRANSPORT_ADDCREATURE: + case SMART_EVENT_NEAR_PLAYERS: return true; default: return false; @@ -572,6 +578,8 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e) case SMART_EVENT_SUMMONED_UNIT_DIES: return sizeof(SmartEvent::summoned); case SMART_EVENT_NEAR_PLAYERS: return sizeof(SmartEvent::nearPlayer); case SMART_EVENT_NEAR_PLAYERS_NEGATION: return sizeof(SmartEvent::nearPlayerNegation); + case SMART_EVENT_NEAR_UNIT: return sizeof(SmartEvent::nearUnit); + case SMART_EVENT_AREA_CASTING: return sizeof(SmartEvent::areaCasting); default: LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an event {} with no unused params specified in SmartAIMgr::CheckUnusedEventParams(), please report this.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetEventType()); @@ -671,7 +679,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e) case SMART_ACTION_SET_COUNTER: return sizeof(SmartAction::setCounter); case SMART_ACTION_STORE_TARGET_LIST: return sizeof(SmartAction::storeTargets); case SMART_ACTION_WP_RESUME: return NO_PARAMS; - case SMART_ACTION_SET_ORIENTATION: return NO_PARAMS; + case SMART_ACTION_SET_ORIENTATION: return sizeof(SmartAction::orientation); case SMART_ACTION_CREATE_TIMED_EVENT: return sizeof(SmartAction::timeEvent); case SMART_ACTION_PLAYMOVIE: return sizeof(SmartAction::movie); case SMART_ACTION_MOVE_TO_POS: return sizeof(SmartAction::moveToPos); @@ -763,6 +771,8 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e) case SMART_ACTION_MUSIC: return sizeof(SmartAction::music); case SMART_ACTION_SET_GUID: return sizeof(SmartAction::setGuid); case SMART_ACTION_DISABLE: return sizeof(SmartAction::disable); + case SMART_ACTION_SET_SCALE: return sizeof(SmartAction::setScale); + case SMART_ACTION_SUMMON_RADIAL: return sizeof(SmartAction::radialSummon); default: LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); @@ -1041,6 +1051,16 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) if (!IsMinMaxValid(e, e.event.targetCasting.repeatMin, e.event.targetCasting.repeatMax)) return false; break; + case SMART_EVENT_AREA_CASTING: + if (e.event.areaCasting.spellId > 0 && !sSpellMgr->GetSpellInfo(e.event.areaCasting.spellId)) + { + LOG_ERROR("scripts.ai.sai", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Spell entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell); + return false; + } + + if (!IsMinMaxValid(e, e.event.areaCasting.repeatMin, e.event.areaCasting.repeatMax)) + return false; + break; case SMART_EVENT_PASSENGER_BOARDED: case SMART_EVENT_PASSENGER_REMOVED: if (!IsMinMaxValid(e, e.event.minMax.repeatMin, e.event.minMax.repeatMax)) @@ -1270,6 +1290,10 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_EVENT_GO_EVENT_INFORM: case SMART_EVENT_NEAR_PLAYERS: case SMART_EVENT_NEAR_PLAYERS_NEGATION: + if (!IsMinMaxValid(e, e.event.nearPlayer.repeatMin, e.event.nearPlayer.repeatMax)) + return false; + break; + case SMART_EVENT_NEAR_UNIT: case SMART_EVENT_TIMED_EVENT_TRIGGERED: case SMART_EVENT_INSTANCE_PLAYER_ENTER: case SMART_EVENT_TRANSPORT_RELOCATE: @@ -1920,6 +1944,8 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_PLAY_CINEMATIC: case SMART_ACTION_SET_GUID: case SMART_ACTION_DISABLE: + case SMART_ACTION_SET_SCALE: + case SMART_ACTION_SUMMON_RADIAL: break; default: LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id); diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index d33716213..6e45ee232 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -206,10 +206,12 @@ enum SMART_EVENT /* AC Custom Events */ SMART_EVENT_AC_START = 100, - SMART_EVENT_NEAR_PLAYERS = 101, // min, radius, first timer, check timer - SMART_EVENT_NEAR_PLAYERS_NEGATION = 102, // min, radius, first timer, check timer + SMART_EVENT_NEAR_PLAYERS = 101, // min, radius, first timer, repeatMin, repeatMax + SMART_EVENT_NEAR_PLAYERS_NEGATION = 102, // max, radius, first timer, repeatMin, repeatMax + SMART_EVENT_NEAR_UNIT = 103, // type (0: creature 1: gob), entry, count, range, timer + SMART_EVENT_AREA_CASTING = 104, // spellId (0: any), range (0: any), repeatMin, repeatMax, checkTimer - SMART_EVENT_AC_END = 103 + SMART_EVENT_AC_END = 105 }; struct SmartEvent @@ -482,17 +484,37 @@ struct SmartEvent uint32 minCount; uint32 radius; uint32 firstTimer; - uint32 checkTimer; + uint32 repeatMin; + uint32 repeatMax; } nearPlayer; struct { - uint32 minCount; + uint32 maxCount; uint32 radius; uint32 firstTimer; - uint32 checkTimer; + uint32 repeatMin; + uint32 repeatMax; } nearPlayerNegation; + struct + { + uint32 type; + uint32 entry; + uint32 count; + uint32 range; + uint32 timer; + } nearUnit; + + struct + { + uint32 spellId; + uint32 range; + uint32 repeatMin; + uint32 repeatMax; + uint32 checkTimer; + } areaCasting; + struct { uint32 param1; @@ -588,7 +610,7 @@ enum SMART_ACTION SMART_ACTION_SET_COUNTER = 63, // id, value, reset (0/1) SMART_ACTION_STORE_TARGET_LIST = 64, // varID, SMART_ACTION_WP_RESUME = 65, // none - SMART_ACTION_SET_ORIENTATION = 66, // quick change, random orientation? (0/1) + SMART_ACTION_SET_ORIENTATION = 66, // quick change, random orientation? (0/1), turnAngle SMART_ACTION_CREATE_TIMED_EVENT = 67, // id, InitialMin, InitialMax, RepeatMin(only if it repeats), RepeatMax(only if it repeats), chance SMART_ACTION_PLAYMOVIE = 68, // entry SMART_ACTION_MOVE_TO_POS = 69, // PointId (optional x,y,z offset), transport, controlled, ContactDistance @@ -693,9 +715,11 @@ enum SMART_ACTION SMART_ACTION_DO_ACTION = 223, // ActionId SMART_ACTION_ATTACK_STOP = 224, // SMART_ACTION_SET_GUID = 225, // Sends the invoker's or the base object's own ObjectGuid to target - SMART_ACTION_DISABLE = 226, // Disable the targeted creatures, setting them Invisible and Immune to All + SMART_ACTION_DISABLE = 226, // state + SMART_ACTION_SET_SCALE = 227, // scale + SMART_ACTION_SUMMON_RADIAL = 228, // summonEntry, summonDuration, repetitions, startAngle, stepAngle, dist - SMART_ACTION_AC_END = 227, // placeholder + SMART_ACTION_AC_END = 229, // placeholder }; enum class SmartActionSummonCreatureFlags @@ -1289,6 +1313,7 @@ struct SmartAction { uint32 quickChange; uint32 random; + uint32 turnAngle; } orientation; struct @@ -1376,6 +1401,21 @@ struct SmartAction { SAIBool state; } disable; + + struct + { + uint32 scale; + } setScale; + + struct + { + uint32 summonEntry; + uint32 summonDuration; + uint32 repetitions; + uint32 startAngle; + uint32 stepAngle; + uint32 dist; + } radialSummon; //! Note for any new future actions //! All parameters must have type uint32 @@ -1777,8 +1817,10 @@ const uint32 SmartAIEventMask[SMART_EVENT_AC_END][2] = { 0, 0 }, // 98 { 0, 0 }, // 99 { 0, 0 }, // 100 - {SMART_EVENT_NEAR_PLAYERS, SMART_SCRIPT_TYPE_MASK_CREATURE }, - {SMART_EVENT_NEAR_PLAYERS_NEGATION, SMART_SCRIPT_TYPE_MASK_CREATURE } + {SMART_EVENT_NEAR_PLAYERS, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, + {SMART_EVENT_NEAR_PLAYERS_NEGATION, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, + {SMART_EVENT_NEAR_UNIT, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, + {SMART_EVENT_AREA_CASTING, SMART_SCRIPT_TYPE_MASK_CREATURE } }; enum SmartEventFlags diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 111f6a091..1e86f067c 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -2394,6 +2394,11 @@ bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, return true; } +CompletedAchievementMap const& AchievementMgr::GetCompletedAchievements() +{ + return _completedAchievements; +} + AchievementGlobalMgr* AchievementGlobalMgr::instance() { static AchievementGlobalMgr instance; diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h index 39e2dd6a9..7b46c58cc 100644 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -300,6 +300,7 @@ public: void RemoveCriteriaProgress(AchievementCriteriaEntry const* entry); CriteriaProgress* GetCriteriaProgress(AchievementCriteriaEntry const* entry); + CompletedAchievementMap const& GetCompletedAchievements(); private: enum ProgressType { PROGRESS_SET, PROGRESS_ACCUMULATE, PROGRESS_HIGHEST, PROGRESS_RESET }; diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index 3fd3a373b..6c9f77ead 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -727,7 +727,7 @@ void AuctionHouseObject::BuildListOwnerItems(WorldPacket& data, Player* player, bool AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player, std::wstring const& wsearchedname, uint32 listfrom, uint8 levelmin, uint8 levelmax, uint8 usable, uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality, - uint32& count, uint32& totalcount, uint8 /*getAll*/, AuctionSortOrderVector const& sortOrder) + uint32& count, uint32& totalcount, uint8 /*getAll*/, AuctionSortOrderVector const& sortOrder, Milliseconds searchTimeout) { uint32 itrcounter = 0; @@ -754,14 +754,11 @@ bool AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player for (AuctionEntryMap::const_iterator itr = _auctionsMap.begin(); itr != _auctionsMap.end(); ++itr) { - if (!AsyncAuctionListingMgr::IsAuctionListingAllowed()) // pussywizard: World::Update is waiting for us... + if ((itrcounter++) % 100 == 0) // check condition every 100 iterations { - if ((itrcounter++) % 100 == 0) // check condition every 100 iterations + if (GetMSTimeDiff(GameTime::GetGameTimeMS(), GetTimeMS()) >= searchTimeout) // pussywizard: stop immediately if diff is high or waiting too long { - if (sWorldUpdateTime.GetAverageUpdateTime() >= 30 || GetMSTimeDiff(GameTime::GetGameTimeMS(), GetTimeMS()) >= 10ms) // pussywizard: stop immediately if diff is high or waiting too long - { - return false; - } + return false; } } diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.h b/src/server/game/AuctionHouse/AuctionHouseMgr.h index 7c8fa5a46..d765cf121 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.h +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.h @@ -162,7 +162,7 @@ public: bool BuildListAuctionItems(WorldPacket& data, Player* player, std::wstring const& searchedname, uint32 listfrom, uint8 levelmin, uint8 levelmax, uint8 usable, uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality, - uint32& count, uint32& totalcount, uint8 getAll, AuctionSortOrderVector const& sortOrder); + uint32& count, uint32& totalcount, uint8 getAll, AuctionSortOrderVector const& sortOrder, Milliseconds searchTimeout); private: AuctionEntryMap _auctionsMap; @@ -184,7 +184,6 @@ public: AuctionHouseObject* GetAuctionsMap(uint32 factionTemplateId); AuctionHouseObject* GetAuctionsMapByHouseId(uint8 auctionHouseId); - AuctionHouseObject* GetBidsMap(uint32 factionTemplateId); Item* GetAItem(ObjectGuid itemGuid) { diff --git a/src/server/game/Entities/Player/KillRewarder.cpp b/src/server/game/Entities/Player/KillRewarder.cpp index e73930602..dfeb8ed6d 100644 --- a/src/server/game/Entities/Player/KillRewarder.cpp +++ b/src/server/game/Entities/Player/KillRewarder.cpp @@ -174,11 +174,11 @@ void KillRewarder::_RewardXP(Player* player, float rate) } } -void KillRewarder::_RewardReputation(Player* player, float rate) +void KillRewarder::_RewardReputation(Player* player) { // 4.3. Give reputation (player must not be on BG). // Even dead players and corpses are rewarded. - player->RewardReputation(_victim, rate); + player->RewardReputation(_victim); } void KillRewarder::_RewardKillCredit(Player* player) @@ -208,7 +208,6 @@ void KillRewarder::_RewardPlayer(Player* player, bool isDungeon) if (!_isPvP || _isBattleGround) { float xpRate = _group ? _groupRate * float(player->GetLevel()) / _aliveSumLevel : /*Personal rate is 100%.*/ 1.0f; // Group rate depends on the sum of levels. - float reputationRate = _group ? _groupRate * float(player->GetLevel()) / _sumLevel : /*Personal rate is 100%.*/ 1.0f; // Group rate depends on the sum of levels. sScriptMgr->OnRewardKillRewarder(player, isDungeon, xpRate); // Personal rate is 100%. if (_xp) @@ -219,7 +218,7 @@ void KillRewarder::_RewardPlayer(Player* player, bool isDungeon) if (!_isBattleGround) { // If killer is in dungeon then all members receive full reputation at kill. - _RewardReputation(player, isDungeon ? 1.0f : reputationRate); + _RewardReputation(player); _RewardKillCredit(player); } } diff --git a/src/server/game/Entities/Player/KillRewarder.h b/src/server/game/Entities/Player/KillRewarder.h index ab6a3a635..6f1fda257 100644 --- a/src/server/game/Entities/Player/KillRewarder.h +++ b/src/server/game/Entities/Player/KillRewarder.h @@ -37,7 +37,7 @@ private: void _RewardHonor(Player* player); void _RewardXP(Player* player, float rate); - void _RewardReputation(Player* player, float rate); + void _RewardReputation(Player* player); void _RewardKillCredit(Player* player); void _RewardPlayer(Player* player, bool isDungeon); void _RewardGroup(); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 240c3a557..b26be3114 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -5858,7 +5858,7 @@ float Player::CalculateReputationGain(ReputationSource source, uint32 creatureOr } // Calculates how many reputation points player gains in victim's enemy factions -void Player::RewardReputation(Unit* victim, float rate) +void Player::RewardReputation(Unit* victim) { if (!victim || victim->GetTypeId() == TYPEID_PLAYER) return; @@ -5887,7 +5887,6 @@ void Player::RewardReputation(Unit* victim, float rate) if (Rep->RepFaction1 && (!Rep->TeamDependent || teamId == TEAM_ALLIANCE)) { float donerep1 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->GetLevel(), static_cast(Rep->RepValue1), ChampioningFaction ? ChampioningFaction : Rep->RepFaction1); - donerep1 *= rate; FactionEntry const* factionEntry1 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction1); if (factionEntry1) @@ -5899,7 +5898,6 @@ void Player::RewardReputation(Unit* victim, float rate) if (Rep->RepFaction2 && (!Rep->TeamDependent || teamId == TEAM_HORDE)) { float donerep2 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->GetLevel(), static_cast(Rep->RepValue2), ChampioningFaction ? ChampioningFaction : Rep->RepFaction2); - donerep2 *= rate; FactionEntry const* factionEntry2 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction2); if (factionEntry2) @@ -13444,7 +13442,10 @@ LootItem* Player::StoreLootItem(uint8 lootSlot, Loot* loot, InventoryResult& msg LootItem* item = loot->LootItemInSlot(lootSlot, this, &qitem, &ffaitem, &conditem); if (!item || item->is_looted) { - SendEquipError(EQUIP_ERR_ALREADY_LOOTED, nullptr, nullptr); + if (!sScriptMgr->CanSendErrorAlreadyLooted(this)) + { + SendEquipError(EQUIP_ERR_ALREADY_LOOTED, nullptr, nullptr); + } return nullptr; } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 046645578..7fdf2c9ab 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2086,7 +2086,7 @@ public: ReputationMgr& GetReputationMgr() { return *m_reputationMgr; } [[nodiscard]] ReputationMgr const& GetReputationMgr() const { return *m_reputationMgr; } [[nodiscard]] ReputationRank GetReputationRank(uint32 faction_id) const; - void RewardReputation(Unit* victim, float rate); + void RewardReputation(Unit* victim); void RewardReputation(Quest const* quest); float CalculateReputationGain(ReputationSource source, uint32 creatureOrQuestLevel, float rep, int32 faction, bool noQuestBonus = false); diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp index 2864ec507..9f8856792 100644 --- a/src/server/game/Handlers/AuctionHouseHandler.cpp +++ b/src/server/game/Handlers/AuctionHouseHandler.cpp @@ -668,23 +668,24 @@ void WorldSession::HandleAuctionListOwnerItems(WorldPacket& recvData) recvData >> listfrom; // not used in fact (this list does not have page control in client) // pussywizard: - const uint32 delay = 4500; - const uint32 now = GameTime::GetGameTimeMS().count(); + const Milliseconds now = GameTime::GetGameTimeMS(); if (_lastAuctionListOwnerItemsMSTime > now) // list is pending return; - uint32 diff = getMSTimeDiff(_lastAuctionListOwnerItemsMSTime, now); + + const Milliseconds delay = Milliseconds(4500); + Milliseconds diff = GetMSTimeDiff(_lastAuctionListOwnerItemsMSTime, now); if (diff > delay) diff = delay; - _lastAuctionListOwnerItemsMSTime = now + delay; // set longest possible here, actual exectuing will change this to getMSTime of that moment - _player->m_Events.AddEvent(new AuctionListOwnerItemsDelayEvent(guid, _player->GetGUID(), true), _player->m_Events.CalculateTime(delay - diff)); + _lastAuctionListOwnerItemsMSTime = now + delay; // set longest possible here, actual executing will change this to getMSTime of that moment + _player->m_Events.AddEvent(new AuctionListOwnerItemsDelayEvent(guid, _player->GetGUID()), _player->m_Events.CalculateTime(delay.count() - diff.count())); } void WorldSession::HandleAuctionListOwnerItemsEvent(ObjectGuid creatureGuid) { LOG_DEBUG("network", "WORLD: Received CMSG_AUCTION_LIST_OWNER_ITEMS"); - _lastAuctionListOwnerItemsMSTime = GameTime::GetGameTimeMS().count(); // pussywizard + _lastAuctionListOwnerItemsMSTime = GameTime::GetGameTimeMS(); // pussywizard Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(creatureGuid, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) @@ -757,17 +758,17 @@ void WorldSession::HandleAuctionListItems(WorldPacket& recvData) } // pussywizard: - const uint32 delay = 2000; - const uint32 now = GameTime::GetGameTimeMS().count(); - uint32 diff = getMSTimeDiff(_lastAuctionListItemsMSTime, now); + const Milliseconds delay = 2s; + const Milliseconds now = GameTime::GetGameTimeMS(); + Milliseconds diff = GetMSTimeDiff(_lastAuctionListItemsMSTime, now); if (diff > delay) { diff = delay; } _lastAuctionListItemsMSTime = now + delay - diff; std::lock_guard guard(AsyncAuctionListingMgr::GetTempLock()); - AsyncAuctionListingMgr::GetTempList().push_back(AuctionListItemsDelayEvent(delay - diff, _player->GetGUID(), guid, searchedname, listfrom, levelmin, levelmax, usable, auctionSlotID, - auctionMainCategory, auctionSubCategory, quality, getAll, sortOrder)); + AsyncAuctionListingMgr::GetTempList().emplace_back(delay - diff, _player->GetGUID(), guid, searchedname, listfrom, levelmin, levelmax, usable, auctionSlotID, + auctionMainCategory, auctionSubCategory, quality, getAll, sortOrder); } void WorldSession::HandleAuctionListPendingSales(WorldPacket& recvData) diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index b5d36cc65..e4a1b3c3c 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -93,6 +93,8 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData) loot = &creature->loot; } + sScriptMgr->OnAfterCreatureLoot(player); + InventoryResult msg; LootItem* lootItem = player->StoreLootItem(lootSlot, loot, msg); if (msg != EQUIP_ERR_OK && lguid.IsItem() && loot->loot_type != LOOT_CORPSE) @@ -209,6 +211,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/) } else { + sScriptMgr->OnAfterCreatureLootMoney(player); player->ModifyMoney(loot->gold); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, loot->gold); diff --git a/src/server/game/Misc/AsyncAuctionListing.cpp b/src/server/game/Misc/AsyncAuctionListing.cpp index d52908e1e..acc657bc9 100644 --- a/src/server/game/Misc/AsyncAuctionListing.cpp +++ b/src/server/game/Misc/AsyncAuctionListing.cpp @@ -22,11 +22,9 @@ #include "Player.h" #include "SpellAuraEffects.h" -uint32 AsyncAuctionListingMgr::auctionListingDiff = 0; -bool AsyncAuctionListingMgr::auctionListingAllowed = false; +Milliseconds AsyncAuctionListingMgr::auctionListingDiff = Milliseconds::zero(); std::list AsyncAuctionListingMgr::auctionListingList; std::list AsyncAuctionListingMgr::auctionListingListTemp; -std::mutex AsyncAuctionListingMgr::auctionListingLock; std::mutex AsyncAuctionListingMgr::auctionListingTempLock; bool AuctionListOwnerItemsDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) @@ -60,18 +58,19 @@ bool AuctionListItemsDelayEvent::Execute() wstrToLower(wsearchedname); + uint32 searchTimeout = sWorld->getIntConfig(CONFIG_AUCTION_HOUSE_SEARCH_TIMEOUT); bool result = auctionHouse->BuildListAuctionItems(data, plr, wsearchedname, _listfrom, _levelmin, _levelmax, _usable, _auctionSlotID, _auctionMainCategory, _auctionSubCategory, _quality, - count, totalcount, _getAll, _sortOrder); + count, totalcount, _getAll, _sortOrder, Milliseconds(searchTimeout)); - if (!result) - return false; - - data.put(0, count); - data << (uint32) totalcount; - data << (uint32) 300; // clientside search cooldown [ms] (gray search button) - plr->GetSession()->SendPacket(&data); + if (result) + { + data.put(0, count); + data << (uint32) totalcount; + data << (uint32) 300; // clientside search cooldown [ms] (gray search button) + plr->GetSession()->SendPacket(&data); + } return true; } diff --git a/src/server/game/Misc/AsyncAuctionListing.h b/src/server/game/Misc/AsyncAuctionListing.h index 40476ed81..110651030 100644 --- a/src/server/game/Misc/AsyncAuctionListing.h +++ b/src/server/game/Misc/AsyncAuctionListing.h @@ -25,30 +25,28 @@ class AuctionListOwnerItemsDelayEvent : public BasicEvent { public: - AuctionListOwnerItemsDelayEvent(ObjectGuid _creatureGuid, ObjectGuid guid, bool o) : creatureGuid(_creatureGuid), playerguid(guid), owner(o) {} + AuctionListOwnerItemsDelayEvent(ObjectGuid _creatureGuid, ObjectGuid guid) : creatureGuid(_creatureGuid), playerguid(guid) {} ~AuctionListOwnerItemsDelayEvent() override {} bool Execute(uint64 e_time, uint32 p_time) override; void Abort(uint64 /*e_time*/) override {} - bool getOwner() { return owner; } private: ObjectGuid creatureGuid; ObjectGuid playerguid; - bool owner; }; class AuctionListItemsDelayEvent { public: - AuctionListItemsDelayEvent(uint32 msTimer, ObjectGuid playerguid, ObjectGuid creatureguid, std::string searchedname, uint32 listfrom, uint8 levelmin, uint8 levelmax, + AuctionListItemsDelayEvent(Milliseconds pickupTimer, ObjectGuid playerguid, ObjectGuid creatureguid, std::string searchedname, uint32 listfrom, uint8 levelmin, uint8 levelmax, uint8 usable, uint32 auctionSlotID, uint32 auctionMainCategory, uint32 auctionSubCategory, uint32 quality, uint8 getAll, AuctionSortOrderVector sortOrder) : - _msTimer(msTimer), _playerguid(playerguid), _creatureguid(creatureguid), _searchedname(searchedname), _listfrom(listfrom), _levelmin(levelmin), _levelmax(levelmax),_usable(usable), + _pickupTimer(pickupTimer), _playerguid(playerguid), _creatureguid(creatureguid), _searchedname(searchedname), _listfrom(listfrom), _levelmin(levelmin), _levelmax(levelmax),_usable(usable), _auctionSlotID(auctionSlotID), _auctionMainCategory(auctionMainCategory), _auctionSubCategory(auctionSubCategory), _quality(quality), _getAll(getAll), _sortOrder(sortOrder) { } bool Execute(); - uint32 _msTimer; + Milliseconds _pickupTimer; ObjectGuid _playerguid; ObjectGuid _creatureguid; std::string _searchedname; @@ -67,23 +65,17 @@ public: class AsyncAuctionListingMgr { public: - static void Update(uint32 diff) { auctionListingDiff += diff; } - static uint32 GetDiff() { return auctionListingDiff; } - static void ResetDiff() { auctionListingDiff = 0; } - static bool IsAuctionListingAllowed() { return auctionListingAllowed; } - static void SetAuctionListingAllowed(bool a) { auctionListingAllowed = a; } - + static void Update(Milliseconds diff) { auctionListingDiff += diff; } + static Milliseconds GetDiff() { return auctionListingDiff; } + static void ResetDiff() { auctionListingDiff = Milliseconds::zero(); } static std::list& GetList() { return auctionListingList; } static std::list& GetTempList() { return auctionListingListTemp; } - static std::mutex& GetLock() { return auctionListingLock; } static std::mutex& GetTempLock() { return auctionListingTempLock; } private: - static uint32 auctionListingDiff; - static bool auctionListingAllowed; + static Milliseconds auctionListingDiff; static std::list auctionListingList; static std::list auctionListingListTemp; - static std::mutex auctionListingLock; static std::mutex auctionListingTempLock; }; diff --git a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp index a2b487147..2c1882d79 100644 --- a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp @@ -913,6 +913,37 @@ bool ScriptMgr::CanSendMail(Player* player, ObjectGuid receiverGuid, ObjectGuid return true; } +bool ScriptMgr::CanSendErrorAlreadyLooted(Player* player) +{ + auto ret = IsValidBoolScript([&](PlayerScript* script) + { + return !script->CanSendErrorAlreadyLooted(player); + }); + + if (ret && *ret) + { + return false; + } + + return true; +} + +void ScriptMgr::OnAfterCreatureLoot(Player* player) +{ + ExecuteScript([&](PlayerScript* script) + { + script->OnAfterCreatureLoot(player); + }); +} + +void ScriptMgr::OnAfterCreatureLootMoney(Player* player) +{ + ExecuteScript([&](PlayerScript* script) + { + script->OnAfterCreatureLootMoney(player); + }); +} + void ScriptMgr::PetitionBuy(Player* player, Creature* creature, uint32& charterid, uint32& cost, uint32& type) { ExecuteScript([&](PlayerScript* script) @@ -986,7 +1017,7 @@ void ScriptMgr::OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, void ScriptMgr::OnUpdateGatheringSkill(Player *player, uint32 skillId, uint32 currentLevel, uint32 gray, uint32 green, uint32 yellow, uint32 &gain) { ExecuteScript([&](PlayerScript* script) { - script->OnUpdateGatheringSkill(player, skillId, gray, green, yellow, currentLevel, gain); + script->OnUpdateGatheringSkill(player, skillId, currentLevel, gray, green, yellow, gain); }); } diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 2a8d76079..27057ee31 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -1483,6 +1483,30 @@ public: virtual void AnticheatUpdateMovementInfo(Player* /*player*/, MovementInfo const& /*movementInfo*/) { } [[nodiscard]] virtual bool AnticheatHandleDoubleJump(Player* /*player*/, Unit* /*mover*/) { return true; } [[nodiscard]] virtual bool AnticheatCheckMovementInfo(Player* /*player*/, MovementInfo const& /*movementInfo*/, Unit* /*mover*/, bool /*jump*/) { return true; } + + /** + * @brief This hook is called, to avoid displaying the error message that the body has already been stripped + * + * @param player Contains information about the Player + * + * @return true Avoiding displaying the error message that the loot has already been taken. + */ + virtual bool CanSendErrorAlreadyLooted(Player* /*player*/) { return true; } + + /** + * @brief It is used when an item is taken from a creature. + * + * @param player Contains information about the Player + * + */ + virtual void OnAfterCreatureLoot(Player* /*player*/) { } + + /** + * @brief After a creature's money is taken + * + * @param player Contains information about the Player + */ + virtual void OnAfterCreatureLootMoney(Player* /*player*/) { } }; class AccountScript : public ScriptObject @@ -2447,6 +2471,9 @@ public: /* PlayerScript */ void OnPlayerEnterCombat(Player* player, Unit* enemy); void OnPlayerLeaveCombat(Player* player); void OnQuestAbandon(Player* player, uint32 questId); + bool CanSendErrorAlreadyLooted(Player* player); + void OnAfterCreatureLoot(Player* player); + void OnAfterCreatureLootMoney(Player* player); // Anti cheat void AnticheatSetSkipOnePacketForASH(Player* player, bool apply); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 556d1f71f..349af359f 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -1079,8 +1079,8 @@ public: // opcodes handlers void HandleEnterPlayerVehicle(WorldPacket& data); void HandleUpdateProjectilePosition(WorldPacket& recvPacket); - uint32 _lastAuctionListItemsMSTime; - uint32 _lastAuctionListOwnerItemsMSTime; + Milliseconds _lastAuctionListItemsMSTime; + Milliseconds _lastAuctionListOwnerItemsMSTime; void HandleTeleportTimeout(bool updateInSessions); bool HandleSocketClosed(); diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 6a8bc2109..bd5e28e21 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -1918,6 +1918,16 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b } } break; + case 34026: // Kill Command + // Dungeon Set 3 + if (caster->HasAura(37483)) + { + if (apply) + { + caster->CastSpell(caster, 37482, true); + } + } + break; } break; case SPELLFAMILY_PALADIN: diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 594d5133d..ce45a5589 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3436,6 +3436,11 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) spell_bonus += int32(0.08f * m_caster->GetTotalAttackPowerValue(BASE_ATTACK)); spell_bonus += int32(0.13f * m_caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask())); break; + case 42463: // Seals of the Pure for Seal of Vengeance/Corruption + case 53739: + if (AuraEffect const* sealsOfPure = m_caster->GetAuraEffect(SPELL_AURA_ADD_PCT_MODIFIER, SPELLFAMILY_PALADIN, 25, 0)) + AddPct(totalDamagePercentMod, sealsOfPure->GetAmount()); + break; case 53385: // Divine Storm deals normalized damage normalized = true; break; diff --git a/src/server/game/World/IWorld.h b/src/server/game/World/IWorld.h index fecbc169b..784a1168d 100644 --- a/src/server/game/World/IWorld.h +++ b/src/server/game/World/IWorld.h @@ -413,6 +413,7 @@ enum WorldIntConfigs CONFIG_LFG_KICK_PREVENTION_TIMER, CONFIG_CHANGE_FACTION_MAX_MONEY, CONFIG_WATER_BREATH_TIMER, + CONFIG_AUCTION_HOUSE_SEARCH_TIMEOUT, INT_CONFIG_VALUE_COUNT }; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index e1b71cdeb..1651ad90d 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1286,6 +1286,8 @@ void World::LoadConfigSettings(bool reload) _bool_configs[CONFIG_ALLOWS_RANK_MOD_FOR_PET_HEALTH] = sConfigMgr->GetOption("Pet.RankMod.Health", true); + _int_configs[CONFIG_AUCTION_HOUSE_SEARCH_TIMEOUT] = sConfigMgr->GetOption("AuctionHouse.SearchTimeout", 1000); + ///- Read the "Data" directory from the config file std::string dataPath = sConfigMgr->GetOption("DataDir", "./"); if (dataPath.empty() || (dataPath.at(dataPath.length() - 1) != '/' && dataPath.at(dataPath.length() - 1) != '\\')) @@ -2352,41 +2354,27 @@ void World::Update(uint32 diff) sScriptMgr->OnPlayerbotUpdate(diff); - // pussywizard: - // acquire mutex now, this is kind of waiting for listing thread to finish it's work (since it can't process next packet) - // so we don't have to do it in every packet that modifies auctions - AsyncAuctionListingMgr::SetAuctionListingAllowed(false); + // pussywizard: handle auctions when the timer has passed + if (_timers[WUPDATE_AUCTIONS].Passed()) { - std::lock_guard guard(AsyncAuctionListingMgr::GetLock()); + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update expired auctions")); - // pussywizard: handle auctions when the timer has passed - if (_timers[WUPDATE_AUCTIONS].Passed()) - { - METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update expired auctions")); + _timers[WUPDATE_AUCTIONS].Reset(); - _timers[WUPDATE_AUCTIONS].Reset(); - - // pussywizard: handle expired auctions, auctions expired when realm was offline are also handled here (not during loading when many required things aren't loaded yet) - sAuctionMgr->Update(); - } - - AsyncAuctionListingMgr::Update(diff); - - if (currentGameTime > _mail_expire_check_timer) - { - sObjectMgr->ReturnOrDeleteOldMails(true); - _mail_expire_check_timer = currentGameTime + 6h; - } - - { - ///
  • Handle session updates when the timer has passed - METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update sessions")); - UpdateSessions(diff); - } + // pussywizard: handle expired auctions, auctions expired when realm was offline are also handled here (not during loading when many required things aren't loaded yet) + sAuctionMgr->Update(); } - // end of section with mutex - AsyncAuctionListingMgr::SetAuctionListingAllowed(true); + AsyncAuctionListingMgr::Update(Milliseconds(diff)); + + if (currentGameTime > _mail_expire_check_timer) + { + sObjectMgr->ReturnOrDeleteOldMails(true); + _mail_expire_check_timer = currentGameTime + 6h; + } + + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update sessions")); + UpdateSessions(diff); ///
  • Handle weather updates when the timer has passed if (_timers[WUPDATE_WEATHERS].Passed()) diff --git a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp index f844d0061..82f3f0d19 100644 --- a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp +++ b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp @@ -157,7 +157,6 @@ void AddSC_isle_of_queldanas(); void AddSC_redridge_mountains(); void AddSC_silverpine_forest(); void AddSC_stormwind_city(); -void AddSC_stranglethorn_vale(); void AddSC_tirisfal_glades(); void AddSC_undercity(); void AddSC_western_plaguelands(); @@ -310,7 +309,6 @@ void AddEasternKingdomsScripts() AddSC_redridge_mountains(); AddSC_silverpine_forest(); AddSC_stormwind_city(); - AddSC_stranglethorn_vale(); AddSC_tirisfal_glades(); AddSC_undercity(); AddSC_western_plaguelands(); diff --git a/src/server/scripts/EasternKingdoms/zone_stranglethorn_vale.cpp b/src/server/scripts/EasternKingdoms/zone_stranglethorn_vale.cpp deleted file mode 100644 index 1686e33d3..000000000 --- a/src/server/scripts/EasternKingdoms/zone_stranglethorn_vale.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by the - * Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -/* ScriptData -SDName: Stranglethorn_Vale -SD%Complete: 100 -SDComment: Quest support: 592 -SDCategory: Stranglethorn Vale -EndScriptData */ - -/* ContentData -npc_yenniku -EndContentData */ - -#include "Player.h" -#include "ScriptMgr.h" -#include "ScriptedCreature.h" -#include "SpellInfo.h" - -/*###### -## npc_yenniku -######*/ - -class npc_yenniku : public CreatureScript -{ -public: - npc_yenniku() : CreatureScript("npc_yenniku") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_yennikuAI(creature); - } - - struct npc_yennikuAI : public ScriptedAI - { - npc_yennikuAI(Creature* creature) : ScriptedAI(creature) - { - bReset = false; - } - - uint32 Reset_Timer; - bool bReset; - - void Reset() override - { - Reset_Timer = 0; - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); - } - - void SpellHit(Unit* caster, SpellInfo const* spell) override - { - if (bReset || spell->Id != 3607) - return; - - if (Player* player = caster->ToPlayer()) - { - if (player->GetQuestStatus(592) == QUEST_STATUS_INCOMPLETE) //Yenniku's Release - { - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STUN); - me->CombatStop(); //stop combat - me->GetThreatMgr().ClearAllThreat(); //unsure of this - me->SetFaction(FACTION_HORDE_GENERIC); - - bReset = true; - Reset_Timer = 60000; - } - } - } - - void JustEngagedWith(Unit* /*who*/) override { } - - void UpdateAI(uint32 diff) override - { - if (bReset) - { - if (Reset_Timer <= diff) - { - EnterEvadeMode(); - bReset = false; - me->SetFaction(FACTION_TROLL_BLOODSCALP); - return; - } - - Reset_Timer -= diff; - - if (me->IsInCombat() && me->GetVictim()) - { - if (Player* player = me->GetVictim()->ToPlayer()) - { - if (player->GetTeamId() == TEAM_HORDE) - { - me->CombatStop(); - me->GetThreatMgr().ClearAllThreat(); - } - } - } - } - - //Return since we have no target - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); - } - }; -}; - -/*###### -## -######*/ - -void AddSC_stranglethorn_vale() -{ - new npc_yenniku(); -} diff --git a/src/server/scripts/Events/midsummer.cpp b/src/server/scripts/Events/midsummer.cpp index 3fe6b35e1..a7b7d5ad7 100644 --- a/src/server/scripts/Events/midsummer.cpp +++ b/src/server/scripts/Events/midsummer.cpp @@ -46,43 +46,6 @@ public: } }; -struct npc_midsummer_bonfire : public ScriptedAI -{ - npc_midsummer_bonfire(Creature* creature) : ScriptedAI(creature) - { - me->IsAIEnabled = true; - goGUID.Clear(); - if (GameObject* go = me->SummonGameObject(GO_MIDSUMMER_BONFIRE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0)) - { - goGUID = go->GetGUID(); - me->RemoveGameObject(go, false); - } - } - - ObjectGuid goGUID; - - void SpellHit(Unit*, SpellInfo const* spellInfo) override - { - if (!goGUID) - return; - - // Extinguish fire - if (spellInfo->Id == SPELL_STAMP_OUT_BONFIRE) - { - if (GameObject* go = ObjectAccessor::GetGameObject(*me, goGUID)) - go->SetPhaseMask(2, true); - } - else if (spellInfo->Id == SPELL_LIGHT_BONFIRE) - { - if (GameObject* go = ObjectAccessor::GetGameObject(*me, goGUID)) - { - go->SetPhaseMask(1, true); - go->SendCustomAnim(1); - } - } - } -}; - struct npc_midsummer_torch_target : public ScriptedAI { npc_midsummer_torch_target(Creature* creature) : ScriptedAI(creature) @@ -542,7 +505,6 @@ void AddSC_event_midsummer_scripts() { // NPCs new go_midsummer_bonfire(); - RegisterCreatureAI(npc_midsummer_bonfire); RegisterCreatureAI(npc_midsummer_torch_target); // Spells diff --git a/src/server/scripts/Kalimdor/zone_feralas.cpp b/src/server/scripts/Kalimdor/zone_feralas.cpp index 5aedbcf76..c99063d71 100644 --- a/src/server/scripts/Kalimdor/zone_feralas.cpp +++ b/src/server/scripts/Kalimdor/zone_feralas.cpp @@ -66,231 +66,7 @@ public: } }; -enum WanderingShay -{ - QUEST_WANDERING_SHAY = 2845, - - SPELL_SHAY_BELL = 11402, - - NPC_ROCKBITER = 7765, - - TALK_0 = 0, - TALK_1 = 1, - TALK_2 = 2, - TALK_3 = 3, - TALK_4 = 4, - - EVENT_WANDERING_START = 1, - EVENT_WANDERING_TALK = 2, - EVENT_WANDERING_RANDOM = 3, - EVENT_FINAL_TALK = 4, - EVENT_CHECK_FOLLOWER = 5 -}; - -class npc_shay_leafrunner : public CreatureScript -{ -public: - npc_shay_leafrunner() : CreatureScript("npc_shay_leafrunner") {} - - struct npc_shay_leafrunnerAI : public ScriptedAI - { - npc_shay_leafrunnerAI(Creature* creature) : ScriptedAI(creature) {} - - void InitializeAI() override - { - me->SetNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); - me->SetImmuneToAll(true); - me->RestoreFaction(); - - _events.Reset(); - _playerGUID.Clear(); - _rockbiterGUID.Clear(); - } - - void JustRespawned() override - { - InitializeAI(); - me->SetHomePosition(me->GetPosition()); - } - - void MoveInLineOfSight(Unit* target) override - { - if (!_playerGUID || target->GetEntry() != NPC_ROCKBITER || !me->IsInRange(target, 0.f, 10.f)) - { - if (!me->IsInCombat() && !me->GetVictim()) - { - if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID)) - { - if (Unit* victim = player->GetVictim()) - { - if (me->CanStartAttack(victim)) - { - AttackStart(victim); - } - } - } - } - - return; - } - - _rockbiterGUID = target->GetGUID(); - - Talk(TALK_4, target); - - me->SetControlled(true, UNIT_STATE_ROOT); - - if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID)) - { - player->GroupEventHappens(QUEST_WANDERING_SHAY, me); - } - - _events.CancelEvent(EVENT_WANDERING_START); - _events.ScheduleEvent(EVENT_FINAL_TALK, 5s); - } - - void EnterEvadeMode(EvadeReason why) override - { - _EnterEvadeMode(why); - - if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID)) - { - me->GetMotionMaster()->MoveFollow(player, 3.f, M_PI); - } - } - - void FailQuest(Player* player, bool despawn) - { - if (player) - { - player->FailQuest(QUEST_WANDERING_SHAY); - - if (Group* group = player->GetGroup()) - { - for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next()) - { - if (Player* member = groupRef->GetSource()) - { - if (member->GetGUID() != player->GetGUID()) - { - member->FailQuest(QUEST_WANDERING_SHAY); - } - } - } - } - } - - if (despawn) - { - me->DespawnOrUnsummon(1); - } - } - - void JustDied(Unit* /*killer*/) override - { - if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID)) - { - FailQuest(player, false); - } - } - - void sQuestAccept(Player* player, Quest const* quest) override - { - if (quest->GetQuestId() == QUEST_WANDERING_SHAY) - { - _playerGUID = player->GetGUID(); - - Talk(TALK_0, player); - - me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); - me->SetImmuneToAll(false); - me->SetFaction(FACTION_ESCORT_N_NEUTRAL_ACTIVE); - me->GetMotionMaster()->MoveFollow(player, 3.f, M_PI); - - _events.ScheduleEvent(EVENT_WANDERING_START, 40s, 70s); - _events.ScheduleEvent(EVENT_CHECK_FOLLOWER, 30s); - } - } - - void SpellHit(Unit* caster, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_SHAY_BELL) - { - _playerGUID = caster->GetGUID(); - - Talk(TALK_1, caster); - - me->GetMotionMaster()->MoveIdle(); - me->GetMotionMaster()->MoveFollow(caster, 3.f, M_PI); - } - } - - void UpdateAI(uint32 diff) override - { - if (UpdateVictim()) - { - DoMeleeAttackIfReady(); - return; - } - - _events.Update(diff); - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_WANDERING_START: - { - Position pos = me->GetFirstCollisionPosition(15.f, rand_norm() * static_cast(2 * M_PI)); - me->GetMotionMaster()->MovePoint(0, pos); - Talk(TALK_2); - _events.ScheduleEvent(EVENT_WANDERING_START, 60s, 70s); - _events.ScheduleEvent(EVENT_WANDERING_TALK, 3s); - _events.ScheduleEvent(EVENT_WANDERING_RANDOM, 8s); - break; - } - case EVENT_WANDERING_TALK: - Talk(TALK_3); - break; - case EVENT_WANDERING_RANDOM: - me->SetHomePosition(me->GetPosition()); - me->GetMotionMaster()->MoveRandom(15.f); - break; - case EVENT_FINAL_TALK: - if (Creature* robckbiter = ObjectAccessor::GetCreature(*me, _rockbiterGUID)) - { - robckbiter->AI()->Talk(TALK_0, me); - } - me->DespawnOrUnsummon(10 * IN_MILLISECONDS); - break; - case EVENT_CHECK_FOLLOWER: - { - Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID); - if (!player || !player->IsAlive() || !me->IsInRange(player, 0.f, 50.f)) - { - FailQuest(player, true); - } - break; - } - default: - break; - } - } - } - - private: - ObjectGuid _playerGUID; - ObjectGuid _rockbiterGUID; - EventMap _events; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_shay_leafrunnerAI(creature); - } -}; - void AddSC_feralas() { new spell_gordunni_trap(); - new npc_shay_leafrunner(); } diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp index 4a17a9542..e8bada84a 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp @@ -97,9 +97,6 @@ public: if (m_pInstance) m_pInstance->SetData(TYPE_IONAR, NOT_STARTED); - - // Ionar is immune to nature damage - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NATURE, true); } void ScheduleEvents(bool spark) diff --git a/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_exarch_maladaar.cpp b/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_exarch_maladaar.cpp index 546210c2a..fc6253e80 100644 --- a/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_exarch_maladaar.cpp +++ b/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_exarch_maladaar.cpp @@ -74,7 +74,10 @@ struct boss_exarch_maladaar : public BossAI _Reset(); ScheduleHealthCheckEvent(25, [&] { Talk(SAY_SUMMON); - DoCastSelf(SPELL_SUMMON_AVATAR); + scheduler.Schedule(100ms, [this](TaskContext) + { + DoCastSelf(SPELL_SUMMON_AVATAR); + }); }); } @@ -133,6 +136,11 @@ struct boss_exarch_maladaar : public BossAI _JustDied(); } + void JustSummoned(Creature* /*creature*/) override + { + // Override JustSummoned() so we don't despawn the Avatar. + } + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_murmur.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_murmur.cpp index 36b10f43f..b1cd844c7 100644 --- a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_murmur.cpp +++ b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_murmur.cpp @@ -208,25 +208,27 @@ class spell_murmur_thundering_storm : public SpellScript } }; -// 33711/38794 - Murmur's Touch -class spell_murmur_touch : public AuraScript +// 33686 - Shockwave (Murmur's Touch final explosion) +class spell_shockwave_knockback : public SpellScript { - PrepareAuraScript(spell_murmur_touch); + PrepareSpellScript(spell_shockwave_knockback); - void HandleAfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + bool Validate(SpellInfo const* /*spellInfo*/) override { - if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) + return ValidateSpellInfo({ SPELL_SHOCKWAVE_SERVERSIDE }); + } + + void HandleOnHit() + { + if (Unit* target = GetHitUnit()) { - if (GetTarget()) - { - GetTarget()->CastSpell(GetTarget(), SPELL_SHOCKWAVE_SERVERSIDE, true); - } + target->CastSpell(target, SPELL_SHOCKWAVE_SERVERSIDE, true); } } void Register() override { - AfterEffectRemove += AuraEffectRemoveFn(spell_murmur_touch::HandleAfterRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + OnHit += SpellHitFn(spell_shockwave_knockback::HandleOnHit); } }; @@ -252,6 +254,6 @@ void AddSC_boss_murmur() { RegisterShadowLabyrinthCreatureAI(boss_murmur); RegisterSpellScript(spell_murmur_thundering_storm); - RegisterSpellScript(spell_murmur_touch); + RegisterSpellScript(spell_shockwave_knockback); RegisterSpellScript(spell_murmur_sonic_boom_effect); } diff --git a/src/server/scripts/Outland/CoilfangReservoir/SlavePens/boss_ahune.cpp b/src/server/scripts/Outland/CoilfangReservoir/SlavePens/boss_ahune.cpp index 55cc12d06..20183553b 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SlavePens/boss_ahune.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SlavePens/boss_ahune.cpp @@ -55,6 +55,8 @@ enum EventSpells SPELL_SUMMON_COLDWAVE = 45952, SPELL_SUMMON_FROSTWIND = 45953, + SPELL_CHILLING_AURA = 46542, + /* SPELL_SUMMON_ICE_SPEAR_BUNNY= 46359, // any dest SPELL_ICE_SPEAR_KNOCKBACK = 46360, // src caster @@ -63,6 +65,11 @@ enum EventSpells */ }; +enum CreatureIds +{ + NPC_AHUNITE_HAILSTONE = 25755 +}; + enum eEvents { EVENT_EMERGE = 1, @@ -81,245 +88,241 @@ enum eEvents EVENT_SPELL_SUMMON_COLDWAVE, }; -class boss_ahune : public CreatureScript +enum Misc { -public: - boss_ahune() : CreatureScript("boss_ahune") { } + SET_GUID_INVOKER = 1 +}; - CreatureAI* GetAI(Creature* pCreature) const override +struct boss_ahune : public ScriptedAI +{ + boss_ahune(Creature* c) : ScriptedAI(c), summons(me) { - return GetTheSlavePensAI(pCreature); + SetCombatMovement(false); + SetEquipmentSlots(false, 54806, EQUIP_UNEQUIP, EQUIP_UNEQUIP); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + InvokerGUID.Clear(); + events.Reset(); + events.RescheduleEvent(EVENT_EMERGE, 12000); + events.RescheduleEvent(EVENT_INVOKER_SAY_1, 1000); + events.RescheduleEvent(EVENT_SUMMON_TOTEMS, 4000); } - struct boss_ahuneAI : public ScriptedAI + EventMap events; + SummonList summons; + ObjectGuid InvokerGUID; + + void StartPhase1() { - boss_ahuneAI(Creature* c) : ScriptedAI(c), summons(me) + me->CastSpell(me, SPELL_AHUNES_SHIELD, true); + events.RescheduleEvent(EVENT_TOTEMS_ATTACK, 80000); + events.RescheduleEvent(EVENT_SPELL_COLD_SLAP, 1200); + events.RescheduleEvent(EVENT_SPELL_SUMMON_HAILSTONE, 2000); + events.RescheduleEvent(EVENT_SPELL_SUMMON_COLDWAVE, 5000); + } + + void JustEngagedWith(Unit* /*who*/) override + { + DoZoneInCombat(); + events.Reset(); + StartPhase1(); + } + + void SetGUID(ObjectGuid guid, int32 id) override + { + if (id == SET_GUID_INVOKER) { - SetCombatMovement(false); - SetEquipmentSlots(false, 54806, EQUIP_UNEQUIP, EQUIP_UNEQUIP); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - InvokerGUID.Clear(); - events.Reset(); - events.RescheduleEvent(EVENT_EMERGE, 12000); - events.RescheduleEvent(EVENT_INVOKER_SAY_1, 1000); - events.RescheduleEvent(EVENT_SUMMON_TOTEMS, 4000); + InvokerGUID = guid; } + } - EventMap events; - SummonList summons; - ObjectGuid InvokerGUID; + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + return; - bool CanBeSeen(Player const* player) override + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) { - if (player->IsGameMaster()) + case 0: + break; + case EVENT_EMERGE: + me->SetVisible(true); + me->CastSpell(me, SPELL_EMERGE_0, false); + events.RescheduleEvent(EVENT_ATTACK, 2000); + break; + case EVENT_SUMMON_TOTEMS: + for (uint8 i = 0; i < 3; ++i) + DoSummon(NPC_TOTEM, TotemPos[i], 10 * 60 * 1000, TEMPSUMMON_TIMED_DESPAWN); + break; + case EVENT_INVOKER_SAY_1: + if (Player* plr = ObjectAccessor::GetPlayer(*me, InvokerGUID)) { - return true; + plr->Say("The Ice Stone has melted!", LANG_UNIVERSAL); + plr->CastSpell(plr, SPELL_MAKE_BONFIRE, true); } - - Group const* group = player->GetGroup(); - return group && sLFGMgr->GetDungeon(group->GetGUID()) == lfg::LFG_DUNGEON_FROST_LORD_AHUNE; - } - - void StartPhase1() - { - me->CastSpell(me, SPELL_AHUNES_SHIELD, true); - events.RescheduleEvent(EVENT_TOTEMS_ATTACK, 80000); - events.RescheduleEvent(EVENT_SPELL_COLD_SLAP, 1200); - events.RescheduleEvent(EVENT_SPELL_SUMMON_HAILSTONE, 2000); - events.RescheduleEvent(EVENT_SPELL_SUMMON_COLDWAVE, 5000); - } - - void JustEngagedWith(Unit* /*who*/) override - { - DoZoneInCombat(); + events.RescheduleEvent(EVENT_INVOKER_SAY_2, 2000); + break; + case EVENT_INVOKER_SAY_2: + if (Player* plr = ObjectAccessor::GetPlayer(*me, InvokerGUID)) + plr->Say("Ahune, your strength grows no more!", LANG_UNIVERSAL); + events.RescheduleEvent(EVENT_INVOKER_SAY_3, 2000); + break; + case EVENT_INVOKER_SAY_3: + if (Player* plr = ObjectAccessor::GetPlayer(*me, InvokerGUID)) + plr->Say("Your frozen reign will not come to pass!", LANG_UNIVERSAL); + break; + case EVENT_ATTACK: events.Reset(); + if (Player* plr = ObjectAccessor::GetPlayer(*me, InvokerGUID)) + AttackStart(plr); + me->SetInCombatWithZone(); + if (!me->IsInCombat()) + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } + else + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + break; + case EVENT_TOTEMS_ATTACK: + for (uint8 i = 0; i < 3; ++i) + if (Creature* bunny = me->FindNearestCreature(NPC_TOTEM_BUNNY_1 + i, 150.0f, true)) + bunny->CastSpell(me, SPELL_TOTEM_BEAM, false); + events.RescheduleEvent(EVENT_SUBMERGE, 10000); + break; + case EVENT_SUBMERGE: + Talk(EMOTE_RETREAT); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->CastSpell(me, SPELL_SUBMERGE_0, true); + me->CastSpell(me, SPELL_SELF_STUN, true); + if (Creature* c = DoSummon(NPC_FROZEN_CORE, *me, 24000, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN)) + { + c->SetHealth(me->GetHealth()); + } + events.Reset(); + events.RescheduleEvent(EVENT_COMBAT_EMERGE, 25000); + events.RescheduleEvent(EVENT_EMERGE_WARNING, 20000); + break; + case EVENT_EMERGE_WARNING: + Talk(EMOTE_RESURFACE); + break; + case EVENT_COMBAT_EMERGE: + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->RemoveAura(SPELL_SELF_STUN); + me->CastSpell(me, SPELL_EMERGE_0, false); + // me->CastSpell(me, SPELL_AHUNE_RESURFACES, true); // done in SummonedCreatureDespawn + me->RemoveAura(SPELL_SUBMERGE_0); + summons.DespawnEntry(NPC_FROZEN_CORE); StartPhase1(); - } + break; - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim() && !me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch(events.ExecuteEvent()) - { - case 0: - break; - case EVENT_EMERGE: - me->SetVisible(true); - me->CastSpell(me, SPELL_EMERGE_0, false); - events.RescheduleEvent(EVENT_ATTACK, 2000); - break; - case EVENT_SUMMON_TOTEMS: - for (uint8 i = 0; i < 3; ++i) - DoSummon(NPC_TOTEM, TotemPos[i], 10 * 60 * 1000, TEMPSUMMON_TIMED_DESPAWN); - break; - case EVENT_INVOKER_SAY_1: - if (Player* plr = ObjectAccessor::GetPlayer(*me, InvokerGUID)) - { - plr->Say("The Ice Stone has melted!", LANG_UNIVERSAL); - plr->CastSpell(plr, SPELL_MAKE_BONFIRE, true); - } - events.RescheduleEvent(EVENT_INVOKER_SAY_2, 2000); - break; - case EVENT_INVOKER_SAY_2: - if (Player* plr = ObjectAccessor::GetPlayer(*me, InvokerGUID)) - plr->Say("Ahune, your strength grows no more!", LANG_UNIVERSAL); - events.RescheduleEvent(EVENT_INVOKER_SAY_3, 2000); - break; - case EVENT_INVOKER_SAY_3: - if (Player* plr = ObjectAccessor::GetPlayer(*me, InvokerGUID)) - plr->Say("Your frozen reign will not come to pass!", LANG_UNIVERSAL); - break; - case EVENT_ATTACK: - events.Reset(); - if (Player* plr = ObjectAccessor::GetPlayer(*me, InvokerGUID)) - AttackStart(plr); - me->SetInCombatWithZone(); - if (!me->IsInCombat()) - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - else - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - break; - case EVENT_TOTEMS_ATTACK: - for (uint8 i = 0; i < 3; ++i) - if (Creature* bunny = me->FindNearestCreature(NPC_TOTEM_BUNNY_1 + i, 150.0f, true)) - bunny->CastSpell(me, SPELL_TOTEM_BEAM, false); - events.RescheduleEvent(EVENT_SUBMERGE, 10000); - break; - case EVENT_SUBMERGE: - Talk(EMOTE_RETREAT); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->CastSpell(me, SPELL_SUBMERGE_0, true); - me->CastSpell(me, SPELL_SELF_STUN, true); - if (Creature* c = DoSummon(NPC_FROZEN_CORE, *me, 24000, TEMPSUMMON_TIMED_DESPAWN)) - { - c->SetHealth(me->GetHealth()); - } - events.Reset(); - events.RescheduleEvent(EVENT_COMBAT_EMERGE, 25000); - events.RescheduleEvent(EVENT_EMERGE_WARNING, 20000); - break; - case EVENT_EMERGE_WARNING: - Talk(EMOTE_RESURFACE); - break; - case EVENT_COMBAT_EMERGE: - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->RemoveAura(SPELL_SELF_STUN); - me->CastSpell(me, SPELL_EMERGE_0, false); - // me->CastSpell(me, SPELL_AHUNE_RESURFACES, true); // done in SummonedCreatureDespawn - me->RemoveAura(SPELL_SUBMERGE_0); - StartPhase1(); - break; - - case EVENT_SPELL_COLD_SLAP: - if (Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 5.0f, true)) - if (target->GetPositionZ() < me->GetPositionZ() + 6.0f) - { - int32 dmg = urand(5500, 6000); - me->CastCustomSpell(target, SPELL_COLD_SLAP, &dmg, nullptr, nullptr, false); - float x, y, z; - target->GetNearPoint(target, x, y, z, target->GetObjectSize(), 30.0f, target->GetAngle(me->GetPositionX(), me->GetPositionY()) + M_PI); - target->GetMotionMaster()->MoveJump(x, y, z + 20.0f, 10.0f, 20.0f); - } - events.RepeatEvent(1500); - break; - case EVENT_SPELL_SUMMON_HAILSTONE: - { - float dist = (float)urand(3, 10); - float angle = rand_norm() * 2 * M_PI; - me->CastSpell(MinionSummonPos.GetPositionX() + cos(angle)*dist, MinionSummonPos.GetPositionY() + std::sin(angle)*dist, MinionSummonPos.GetPositionZ(), SPELL_SUMMON_HAILSTONE, false); - events.RepeatEvent(30000); - } - break; - case EVENT_SPELL_SUMMON_COLDWAVE: - for (uint8 i = 0; i < 2; ++i) - { - float dist = (float)urand(3, 10); - float angle = rand_norm() * 2 * M_PI; - me->CastSpell(MinionSummonPos.GetPositionX() + cos(angle)*dist, MinionSummonPos.GetPositionY() + std::sin(angle)*dist, MinionSummonPos.GetPositionZ(), SPELL_SUMMON_COLDWAVE, false); - } - { - float dist = (float)urand(3, 10); - float angle = rand_norm() * 2 * M_PI; - me->CastSpell(MinionSummonPos.GetPositionX() + cos(angle)*dist, MinionSummonPos.GetPositionY() + std::sin(angle)*dist, MinionSummonPos.GetPositionZ(), SPELL_SUMMON_FROSTWIND, false); - } - events.RepeatEvent(6000); - break; - - default: - break; - } - - DoMeleeAttackIfReady(); - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - - void EnterEvadeMode(EvadeReason why) override - { - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - events.Reset(); - summons.DespawnAll(); - me->DespawnOrUnsummon(1); - - ScriptedAI::EnterEvadeMode(why); - } - - void JustSummoned(Creature* summon) override - { - if (summon) - { - summons.Summon(summon); - summon->SetInCombatWithZone(); - } - } - - void SummonedCreatureDespawn(Creature* summon) override - { - if (summon && summon->GetEntry() == NPC_FROZEN_CORE) - { - if (summon->GetHealth() > 0) + case EVENT_SPELL_COLD_SLAP: + if (Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 5.0f, true)) + if (target->GetPositionZ() < me->GetPositionZ() + 6.0f) { - me->SetHealth(summon->GetHealth()); - summon->CastSpell(summon, SPELL_AHUNE_RESURFACES, true); + int32 dmg = urand(5500, 6000); + me->CastCustomSpell(target, SPELL_COLD_SLAP, &dmg, nullptr, nullptr, false); + float x, y, z; + target->GetNearPoint(target, x, y, z, target->GetObjectSize(), 30.0f, target->GetAngle(me->GetPositionX(), me->GetPositionY()) + M_PI); + target->GetMotionMaster()->MoveJump(x, y, z + 20.0f, 10.0f, 20.0f); } - else - Unit::Kill(me, me, false); + events.RepeatEvent(1500); + break; + case EVENT_SPELL_SUMMON_HAILSTONE: + { + float dist = (float)urand(3, 10); + float angle = rand_norm() * 2 * M_PI; + me->CastSpell(MinionSummonPos.GetPositionX() + cos(angle) * dist, MinionSummonPos.GetPositionY() + std::sin(angle) * dist, MinionSummonPos.GetPositionZ(), SPELL_SUMMON_HAILSTONE, false); + } + break; + case EVENT_SPELL_SUMMON_COLDWAVE: + for (uint8 i = 0; i < 2; ++i) + { + float dist = (float)urand(3, 10); + float angle = rand_norm() * 2 * M_PI; + me->CastSpell(MinionSummonPos.GetPositionX() + cos(angle) * dist, MinionSummonPos.GetPositionY() + std::sin(angle) * dist, MinionSummonPos.GetPositionZ(), SPELL_SUMMON_COLDWAVE, false); + } + { + float dist = (float)urand(3, 10); + float angle = rand_norm() * 2 * M_PI; + me->CastSpell(MinionSummonPos.GetPositionX() + cos(angle) * dist, MinionSummonPos.GetPositionY() + std::sin(angle) * dist, MinionSummonPos.GetPositionZ(), SPELL_SUMMON_FROSTWIND, false); + } + events.RepeatEvent(12000); + break; + + default: + break; + } + + DoMeleeAttackIfReady(); + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + + void EnterEvadeMode(EvadeReason why) override + { + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + events.Reset(); + summons.DespawnAll(); + me->DespawnOrUnsummon(1); + + ScriptedAI::EnterEvadeMode(why); + } + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + summon->SetInCombatWithZone(); + + if (summon->GetEntry() == NPC_AHUNITE_HAILSTONE) + { + // Doesn't work when cast normally or when added to + // creature template addon. Needs further investigation. + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_CHILLING_AURA)) + { + Aura::TryRefreshStackOrCreate(spellInfo, MAX_EFFECT_MASK, summon, summon); } } + } - void JustDied(Unit* /*killer*/) override + void SummonedCreatureDespawn(Creature* summon) override + { + if (summon && summon->GetEntry() == NPC_FROZEN_CORE) { - summons.DespawnAll(); - me->DespawnOrUnsummon(15000); - if (GameObject* chest = me->SummonGameObject(187892, MinionSummonPos.GetPositionX(), MinionSummonPos.GetPositionY(), MinionSummonPos.GetPositionZ(), M_PI / 2, 0.0f, 0.0f, 0.0f, 0.0f, 900000000)) // loot - me->RemoveGameObject(chest, false); - - bool finished = false; - Map::PlayerList const& players = me->GetMap()->GetPlayers(); - if (!players.IsEmpty()) - for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) - if (Player* player = i->GetSource()) - { - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, 25740, 1, me); - - if (player->GetGroup() && !finished) - { - finished = true; - sLFGMgr->FinishDungeon(player->GetGroup()->GetGUID(), lfg::LFG_DUNGEON_FROST_LORD_AHUNE, me->FindMap()); - } - } + if (summon->GetHealth() > 0) + { + me->SetHealth(summon->GetHealth()); + summon->CastSpell(summon, SPELL_AHUNE_RESURFACES, true); + } + else + Unit::Kill(me, me, false); } - }; + } + + void JustDied(Unit* /*killer*/) override + { + summons.DespawnAll(); + me->DespawnOrUnsummon(15000); + if (GameObject* chest = me->SummonGameObject(187892, MinionSummonPos.GetPositionX(), MinionSummonPos.GetPositionY(), MinionSummonPos.GetPositionZ(), M_PI / 2, 0.0f, 0.0f, 0.0f, 0.0f, 900000000)) // loot + me->RemoveGameObject(chest, false); + + bool finished = false; + + me->GetMap()->DoForAllPlayers([&](Player* player) + { + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, 25740, 1, me); + + if (player->GetGroup() && !finished) + { + finished = true; + sLFGMgr->FinishDungeon(player->GetGroup()->GetGUID(), lfg::LFG_DUNGEON_FROST_LORD_AHUNE, me->FindMap()); + } + }); + } }; class go_ahune_ice_stone : public GameObjectScript @@ -331,8 +334,18 @@ public: { if (!player || !go) return true; - if (!player->HasItemCount(ITEM_MAGMA_TOTEM)) - return true; + + if (!player->IsGameMaster()) + { + if (Group const* group = player->GetGroup()) + { + if (sLFGMgr->GetDungeon(group->GetGUID()) != lfg::LFG_DUNGEON_FROST_LORD_AHUNE) + { + return true; + } + } + } + if (go->FindNearestCreature(NPC_AHUNE, 200.0f, true)) return true; @@ -345,10 +358,20 @@ public: { if (!player || !go) return true; + + if (!player->IsGameMaster()) + { + if (Group const* group = player->GetGroup()) + { + if (sLFGMgr->GetDungeon(group->GetGUID()) != lfg::LFG_DUNGEON_FROST_LORD_AHUNE) + { + return true; + } + } + } + if (action != GOSSIP_ACTION_INFO_DEF + 1337) return true; - if (!player->HasItemCount(ITEM_MAGMA_TOTEM)) - return true; if (go->FindNearestCreature(NPC_AHUNE, 200.0f, true)) return true; @@ -360,7 +383,11 @@ public: c->SetVisible(false); c->SetDisplayId(AHUNE_DEFAULT_MODEL); c->SetFloatValue(UNIT_FIELD_COMBATREACH, 18.0f); - CAST_AI(boss_ahune::boss_ahuneAI, c->AI())->InvokerGUID = player->GetGUID(); + if (c->AI()) + { + c->AI()->SetGUID(player->GetGUID(), SET_GUID_INVOKER); + } + if (Creature* bunny = go->SummonCreature(NPC_AHUNE_SUMMON_LOC_BUNNY, AhuneSummonPos, TEMPSUMMON_TIMED_DESPAWN, 12000)) if (Creature* crystal_trigger = go->SummonCreature(WORLD_TRIGGER, go->GetPositionX(), go->GetPositionY(), 5.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 12000)) crystal_trigger->CastSpell(bunny, SPELL_STARTING_BEAM, false); @@ -371,30 +398,8 @@ public: } }; -class npc_ahune_frozen_core : public CreatureScript -{ -public: - npc_ahune_frozen_core() : CreatureScript("npc_ahune_frozen_core") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetTheSlavePensAI(pCreature); - } - - struct npc_ahune_frozen_coreAI : public NullCreatureAI - { - npc_ahune_frozen_coreAI(Creature* c) : NullCreatureAI(c) {} - - void JustDied(Unit* /*killer*/) override - { - me->DespawnOrUnsummon(); - } - }; -}; - void AddSC_boss_ahune() { new go_ahune_ice_stone(); - new boss_ahune(); - new npc_ahune_frozen_core(); + RegisterTheSlavePensCreatureAI(boss_ahune); } diff --git a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_mekgineer_steamrigger.cpp b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_mekgineer_steamrigger.cpp index 25ef2b8e7..b075d17df 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_mekgineer_steamrigger.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_mekgineer_steamrigger.cpp @@ -30,8 +30,6 @@ enum MekgineerSteamrigger SPELL_SAW_BLADE = 31486, SPELL_ELECTRIFIED_NET = 35107, SPELL_ENRAGE = 26662, - SPELL_REPAIR_N = 31532, - SPELL_REPAIR_H = 37936, SPELL_SUMMON_MECHANICS_1 = 31528, SPELL_SUMMON_MECHANICS_2 = 31529, diff --git a/src/server/scripts/Outland/CoilfangReservoir/underbog/boss_swamplord_muselek.cpp b/src/server/scripts/Outland/CoilfangReservoir/underbog/boss_swamplord_muselek.cpp index 9b310f2e6..58e401a28 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/underbog/boss_swamplord_muselek.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/underbog/boss_swamplord_muselek.cpp @@ -85,7 +85,15 @@ struct boss_swamplord_muselek : public BossAI bool CanShootVictim() { - return me->GetVictim() && !me->IsWithinRange(me->GetVictim(), 10.0f) && me->IsWithinLOSInMap(me->GetVictim()); + Unit* victim = me->GetVictim(); + + if (!victim || !me->IsWithinLOSInMap(victim) || !me->IsWithinRange(victim, 30.f) || me->IsWithinRange(victim, 10.f)) + { + _canChase = true; + return false; + } + + return true; } void JustEngagedWith(Unit* /*who*/) override @@ -100,6 +108,8 @@ struct boss_swamplord_muselek : public BossAI me->LoadEquipment(1, true); DoCastVictim(SPELL_SHOOT); me->GetMotionMaster()->Clear(); + me->StopMoving(); + _canChase = false; } else if (_canChase) { @@ -121,7 +131,7 @@ struct boss_swamplord_muselek : public BossAI context.Repeat(20s, 30s); }).Schedule(30s, 40s, [this](TaskContext context) { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, false, true)) + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, false, true)) { _markTarget = target->GetGUID(); _canChase = false; @@ -135,6 +145,7 @@ struct boss_swamplord_muselek : public BossAI { me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveForwards(me->GetVictim(), 10.0f); + _canChase = false; } me->m_Events.AddEventAtOffset([this]() diff --git a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp index 64a274f6a..025fc4fbb 100644 --- a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp @@ -17,6 +17,7 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "TaskScheduler.h" #include "hellfire_ramparts.h" enum Says @@ -83,11 +84,6 @@ struct boss_vazruden_the_herald : public BossAI } } - void JustDied(Unit*) override - { - instance->SetBossState(DATA_VAZRUDEN, DONE); - } - void MovementInform(uint32 type, uint32 id) override { if (type == POINT_MOTION_TYPE && id == POINT_MIDDLE) @@ -105,7 +101,7 @@ struct boss_vazruden_the_herald : public BossAI { Talk(SAY_INTRO); me->GetMotionMaster()->MovePoint(POINT_MIDDLE, -1406.5f, 1746.5f, 85.0f, false); - me->setActive(true); + _JustEngagedWith(); } else if (summons.size() == 0) { @@ -139,11 +135,11 @@ struct boss_vazruden_the_herald : public BossAI } }; -struct boss_nazan : public BossAI +struct boss_nazan : public ScriptedAI { - boss_nazan(Creature* creature) : BossAI(creature, DATA_VAZRUDEN) + boss_nazan(Creature* creature) : ScriptedAI(creature) { - scheduler.SetValidator([this] + _scheduler.SetValidator([this] { return !me->HasUnitState(UNIT_STATE_CASTING); }); @@ -162,11 +158,11 @@ struct boss_nazan : public BossAI void JustEngagedWith(Unit*) override { - scheduler.CancelGroup(GROUP_PHASE_2); - scheduler.Schedule(5ms, GROUP_PHASE_1, [this](TaskContext context) + _scheduler.CancelAll(); + _scheduler.Schedule(5ms, GROUP_PHASE_1, [this](TaskContext context) { me->GetMotionMaster()->MovePoint(POINT_FLIGHT, NazanPos[urand(0, 2)], false); - scheduler.DelayAll(7s); + _scheduler.DelayAll(7s); context.Repeat(30s); }).Schedule(5s, GROUP_PHASE_1, [this](TaskContext context) { @@ -191,6 +187,7 @@ struct boss_nazan : public BossAI { if (param == ACTION_FLY_DOWN) { + _scheduler.CancelGroup(GROUP_PHASE_1); Talk(EMOTE_NAZAN); me->SetReactState(REACT_PASSIVE); me->InterruptNonMeleeSpells(true); @@ -205,9 +202,8 @@ struct boss_nazan : public BossAI me->SetCanFly(false); me->SetDisableGravity(false); me->SetReactState(REACT_AGGRESSIVE); - scheduler.CancelGroup(GROUP_PHASE_1); me->GetMotionMaster()->MoveChase(me->GetVictim()); - scheduler.Schedule(5s, GROUP_PHASE_2, [this](TaskContext context) + _scheduler.Schedule(5s, GROUP_PHASE_2, [this](TaskContext context) { DoCastVictim(SPELL_CONE_OF_FIRE); context.Repeat(12s); @@ -216,9 +212,10 @@ struct boss_nazan : public BossAI DoCastRandomTarget(SPELL_FIREBALL); context.Repeat(4s, 6s); }); + if (IsHeroic()) { - scheduler.Schedule(10s, GROUP_PHASE_2, [this](TaskContext context) + _scheduler.Schedule(10s, GROUP_PHASE_2, [this](TaskContext context) { DoCastSelf(SPELL_BELLOWING_ROAR); context.Repeat(30s); @@ -227,24 +224,28 @@ struct boss_nazan : public BossAI } } - void UpdateAI(uint32 /*diff*/) override + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + _scheduler.Update(diff, [this] + { + if (!me->IsLevitating()) + DoMeleeAttackIfReady(); + }); - if (!me->IsLevitating()) - DoMeleeAttackIfReady(); } + +private: + TaskScheduler _scheduler; }; -struct boss_vazruden : public BossAI +struct boss_vazruden : public ScriptedAI { - boss_vazruden(Creature* creature) : BossAI(creature, DATA_VAZRUDEN) + boss_vazruden(Creature* creature) : ScriptedAI(creature) { - scheduler.SetValidator([this] + _scheduler.SetValidator([this] { return !me->HasUnitState(UNIT_STATE_CASTING); }); @@ -263,7 +264,7 @@ struct boss_vazruden : public BossAI void JustEngagedWith(Unit*) override { - scheduler.Schedule(5s, [this](TaskContext /*context*/) + _scheduler.Schedule(5s, [this](TaskContext /*context*/) { Talk(SAY_AGGRO); }).Schedule(4s, [this](TaskContext context) @@ -280,7 +281,7 @@ struct boss_vazruden : public BossAI _hasSpoken = true; Talk(SAY_KILL); } - scheduler.Schedule(6s, [this](TaskContext /*context*/) + _scheduler.Schedule(6s, [this](TaskContext /*context*/) { _hasSpoken = false; }); @@ -305,13 +306,16 @@ struct boss_vazruden : public BossAI if (!UpdateVictim()) return; - scheduler.Update(diff); - DoMeleeAttackIfReady(); + _scheduler.Update(diff, [this] + { + DoMeleeAttackIfReady(); + }); } private: bool _hasSpoken; bool _nazanCalled; + TaskScheduler _scheduler; }; class spell_vazruden_fireball : public SpellScript diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp index 5638bcbb3..79568a64b 100644 --- a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp +++ b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp @@ -144,17 +144,21 @@ class spell_capacitus_polarity_charge : public SpellScript void HandleTargets(std::list& targetList) { uint8 count = 0; - for (std::list::iterator ihit = targetList.begin(); ihit != targetList.end(); ++ihit) - if ((*ihit)->GetGUID() != GetCaster()->GetGUID()) - if (Player* target = (*ihit)->ToPlayer()) + for (auto& ihit : targetList) + if (ihit->GetGUID() != GetCaster()->GetGUID()) + if (Player* target = ihit->ToPlayer()) if (target->HasAura(GetTriggeringSpell()->Id)) ++count; + uint32 spellId = GetSpellInfo()->Id == SPELL_POSITIVE_CHARGE ? SPELL_POSITIVE_CHARGE_STACK : SPELL_NEGATIVE_CHARGE_STACK; if (count) { - uint32 spellId = GetSpellInfo()->Id == SPELL_POSITIVE_CHARGE ? SPELL_POSITIVE_CHARGE_STACK : SPELL_NEGATIVE_CHARGE_STACK; GetCaster()->SetAuraStack(spellId, GetCaster(), count); } + else + { + GetCaster()->RemoveAurasDueToSpell(spellId); + } } void HandleDamage(SpellEffIndex /*effIndex*/) @@ -174,6 +178,29 @@ class spell_capacitus_polarity_charge : public SpellScript } }; +class spell_capacitus_polarity_charge_aura : public AuraScript +{ + PrepareAuraScript(spell_capacitus_polarity_charge_aura); + + void HandleAfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) + { + Unit* target = GetTarget(); + if (!target) + return; + + target->RemoveAurasDueToSpell(SPELL_POSITIVE_CHARGE_STACK); + target->RemoveAurasDueToSpell(SPELL_NEGATIVE_CHARGE_STACK); + } + } + + void Register() override + { + AfterEffectRemove += AuraEffectRemoveFn(spell_capacitus_polarity_charge_aura::HandleAfterRemove, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + } +}; + class spell_capacitus_polarity_shift : public SpellScript { PrepareSpellScript(spell_capacitus_polarity_shift); @@ -194,5 +221,6 @@ void AddSC_boss_mechano_lord_capacitus() { RegisterMechanarCreatureAI(boss_mechano_lord_capacitus); RegisterSpellScript(spell_capacitus_polarity_charge); + RegisterSpellScript(spell_capacitus_polarity_charge_aura); RegisterSpellScript(spell_capacitus_polarity_shift); }