├── generate_sql_files.sh ├── .gitignore ├── docs ├── sql.md ├── gm │ └── commands.md ├── random │ └── aggressive_stormwind_npcs.md ├── infrastructure.md ├── model_display_id.md ├── entry-ids.md ├── data.md ├── creating-quests.md └── 03-the-cartographers.example.sql ├── scripts ├── functions.sh ├── azerothcore_source.sh ├── os.sh ├── firewall.sh ├── backup-database.sh ├── azerothcore_modules.sh ├── azerothcore_data.sh ├── azerothcore_compile.sh ├── azerothcore_worldserver_run.sh ├── import_sql.sh ├── systemd.sh ├── azerothcore_configs.sh └── azerothcore_database.sh ├── clean.sh ├── configurations ├── 50-server.cnf ├── modules │ └── SoloLfg.conf.dist └── authserver.conf ├── sql ├── world │ ├── a-01-quality-of-life.sql │ ├── a-06-various-spawnable-npcs.sql │ ├── a-05-various-spawnable-objects.sql │ ├── a-02-starting-mount-accessiblity.sql │ └── a-03-better-herb-spawns.sql └── auth │ └── a-00-initial-database-setup-gm-account.sql ├── rebuild.sh ├── setup.sh ├── LICENSE ├── kill-everything.sh ├── config.sh.example ├── config.ptr.sh.example └── README.md /generate_sql_files.sh: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyo 2 | *.pyc 3 | venv/ 4 | living-world.*.sh 5 | sql/imported -------------------------------------------------------------------------------- /docs/sql.md: -------------------------------------------------------------------------------- 1 | # SQL 2 | 3 | Various useful SQL statements. 4 | 5 | ## Finding Items 6 | 7 | ```sql 8 | SELECT name,entry,class,subclass,requiredlevel 9 | FROM item_template 10 | WHERE entry = 24064; 11 | ``` 12 | -------------------------------------------------------------------------------- /scripts/functions.sh: -------------------------------------------------------------------------------- 1 | 2 | # Just some useful functions to help along the way 3 | 4 | # Used as a way of printing errors and exiting 5 | error() { 6 | echo "ERROR: ${1} -- Stopping!" 7 | exit 1 8 | } 9 | 10 | warning() { 11 | echo "WARNING: ${1} -- Continuing..." 12 | } 13 | 14 | info() { 15 | echo "INFO: ${1}" 16 | } 17 | -------------------------------------------------------------------------------- /clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export AZEROTHCORE_SOURCE_DIR=azerothcore 4 | export AZEROTHCORE_SERVER_DIR=azerothcore-server 5 | 6 | rm -rf "${HOME}/${AZEROTHCORE_SOURCE_DIR}" 7 | rm -rf "${HOME}/${AZEROTHCORE_SERVER_DIR}" 8 | 9 | sudo mysql -e "drop database acore_auth;" 10 | sudo mysql -e "drop database acore_characters;" 11 | sudo mysql -e "drop database acore_world;" 12 | -------------------------------------------------------------------------------- /configurations/50-server.cnf: -------------------------------------------------------------------------------- 1 | # MariaDB server configuration 2 | 3 | [server] 4 | # No config 5 | 6 | [embedded] 7 | # No config 8 | 9 | [mariadb] 10 | # No config 11 | 12 | [mariadb-10.6] 13 | # No config 14 | 15 | [mysqld] 16 | pid-file = /run/mysqld/mysqld.pid 17 | basedir = /usr 18 | expire_logs_days = 10 19 | character-set-server = utf8mb4 20 | collation-server = utf8mb4_general_ci 21 | -------------------------------------------------------------------------------- /sql/world/a-01-quality-of-life.sql: -------------------------------------------------------------------------------- 1 | 2 | -- Gives the player a small, but decent, extra bag to work with. 3 | DELETE FROM `playercreateinfo_item` WHERE itemid=16057 and amount=1; 4 | INSERT INTO `playercreateinfo_item` (`race`, `class`, `itemid`, `amount`, `Note`) VALUES (0, 0, 16057, 1, "Explorer's Knapsack"); 5 | 6 | -- Update the "Chocolate Celebration Cake" to allow level 10+ to use it 7 | UPDATE `item_template` SET `RequiredLevel` = 10 WHERE `entry` = 42436; 8 | UPDATE `item_template` SET `RequiredLevel` = 10 WHERE `entry` = 42433; -------------------------------------------------------------------------------- /docs/gm/commands.md: -------------------------------------------------------------------------------- 1 | # GM Commands 2 | 3 | useful GM commands I use over and over during development. 4 | 5 | - `.additem #itemid/[#itemname]/#shift-click-item-link #itemcount` 6 | - `.cheat *` 7 | - `.modify money #copper` 8 | - `.appear #char` 9 | - `.tele #place` 10 | - `.summon #char` 11 | - `.learn all *` 12 | - `.quest *` 13 | - `.quest remove #id` is a useful one for quest development 14 | - `.gobject add #id` 15 | - `.gobject delete #guid` 16 | - `.setskill #id #level #level` (?) 17 | - `.setskill 762 300 300` (riding 300) -------------------------------------------------------------------------------- /docs/random/aggressive_stormwind_npcs.md: -------------------------------------------------------------------------------- 1 | # Agressive Stormwind NPCs 2 | 3 | The following SQL will make the listed NPC IDs aggressive to the relevant factions: 4 | 5 | ```sql 6 | -- Makle the NPCs Stormwind faction `11` (agressive) versus `12` 7 | -- Make them all guards so they attack. 8 | UPDATE `creature_template` SET 9 | `unit_flags` = 0, 10 | `faction` = 11, 11 | `type_flags` = 4096, 12 | `flags_extra` = 32768 13 | WHERE entry IN ( 14 | -- Update these to the IDs you're interested in 15 | 927,74,514,797,913,54,2046,1985,6749,253,295,465,151,6778,3935,1430,241,66,240 16 | ); 17 | ``` 18 | -------------------------------------------------------------------------------- /configurations/modules/SoloLfg.conf.dist: -------------------------------------------------------------------------------- 1 | [worldserver] 2 | 3 | ################################################################################################### 4 | # SOLO LFG 5 | ################################################################################################### 6 | 7 | # EnableSoloLfg 8 | # Description: Enable the module 9 | # Default: 1 - (Enabled) 10 | # 0 - (Disabled) 11 | 12 | 13 | LFG.SoloMode = 1 14 | 15 | # AnnounceSoloLfg 16 | # Description: Announce if enabled 17 | # Default: true - (Enabled) 18 | # false - (Disabled) 19 | 20 | SoloLFG.Announce = false 21 | 22 | 23 | ################################################################################################### -------------------------------------------------------------------------------- /docs/infrastructure.md: -------------------------------------------------------------------------------- 1 | # Infrastructure 2 | 3 | Random bits of infrastructure documentation for doing various things with networks, VMs, and more. 4 | 5 | ## DigitalOcean Testing VM 6 | 7 | Spin up a testing VM for playing around with, or recording Machinima. 8 | 9 | ```shell 10 | doctl compute droplet create \ 11 | --context $DO_CONTEXT \ 12 | --ssh-keys $DO_SSH_KEY_FINGERPRINT \ 13 | --image ubuntu-22-04-x64 \ 14 | --size c-4 \ 15 | --region syd1 \ 16 | --vpc-uuid 112d689c-5cfa-478f-8ca5-300091af6f27 \ 17 | --enable-monitoring \ 18 | wow-testing 19 | ``` 20 | 21 | This requires doing `doctl auth init --context wow` and providing a valid DO API token. 22 | 23 | Then you can do: 24 | 25 | ```shell 26 | doctl --context wow compute droplet list --format Name,PublicIPV4 27 | ``` 28 | -------------------------------------------------------------------------------- /rebuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script **is not** idempotent: it's a one-time thing. 4 | # If you do run it several times, then things should be OK, 5 | # but there's no guarantee. 6 | 7 | # This script is designed to make it easier to add a new 8 | # module to the system, have it compiled against the latest 9 | # code, have any new SQL imported, and that's it. It skips 10 | # all the OS level stuff and assumes at least one run of 11 | # setup.sh has taken place on the system. 12 | 13 | source $1 14 | export WHERE_WAS_I=$(pwd) 15 | 16 | if [ "$RUN_AZEROTHCORE_SOURCE" == true ]; then; . scripts/azerothcore_source.sh; fi 17 | if [ "$RUN_AZEROTHCORE_MODULES" == true ]; then; . scripts/azerothcore_modules.sh; fi 18 | if [ "$RUN_AZEROTHCORE_COMPILE" == true ]; then; . scripts/azerothcore_compile.sh; fi 19 | if [ "$RUN_IMPORT_SQL" == true ]; then; . scripts/import_sql.sh; fi 20 | 21 | sudo systemctl restart azerothcore-world-server.service 22 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ** Backup your data/configs/files ** 4 | 5 | # This script **is not** idempotent: it's a one-time thing. 6 | # If you do run it several times, then things should be OK, 7 | # but there's no guarantee. 8 | 9 | source scripts/functions.sh 10 | 11 | # Need a config file to work with 12 | if [ "$1" = "" ]; then error "Did you forget to provide a configuration file?"; else source $1; fi 13 | 14 | [ "$RUN_OS" == true ] && . scripts/os.sh 15 | [ "$RUN_FIREWALL" == true ] && . scripts/firewall.sh 16 | [ "$RUN_AZEROTHCORE_SOURCE" == true ] && . scripts/azerothcore_source.sh 17 | [ "$RUN_AZEROTHCORE_DATABASE" == true ] && . scripts/azerothcore_database.sh 18 | [ "$RUN_AZEROTHCORE_DATA" == true ] && . scripts/azerothcore_data.sh 19 | [ "$RUN_AZEROTHCORE_MODULES" == true ] && . scripts/azerothcore_modules.sh 20 | [ "$RUN_AZEROTHCORE_COMPILE" == true ] && . scripts/azerothcore_compile.sh 21 | [ "$RUN_AZEROTHCORE_CONFIGS" == true ] && . scripts/azerothcore_configs.sh 22 | [ "$RUN_IMPORT_SQL" == true ] && . scripts/import_sql.sh 23 | [ "$RUN_SYSTEMD" == true ] && . scripts/systemd.sh 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Michael Crilly 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/model_display_id.md: -------------------------------------------------------------------------------- 1 | # Model IDs and their attributes 2 | 3 | ## Human Males 4 | 5 | - 6 | 7 | ## Human Females 8 | 9 | - 10 | 11 | ## Night Elf Males 12 | 13 | - 4405 14 | - 9549 15 | - 2276 16 | - 2267 17 | - 5071 18 | - 5070 19 | 20 | ## Night Elf Females 21 | 22 | - 4399 23 | - 5441 24 | - 2198 25 | - 2212 26 | - 2203 27 | - 2202 28 | - 11048 29 | - 6840 30 | 31 | ## Tree Man Thing 32 | 33 | - 2451 34 | 35 | ## Deer 36 | 37 | - 347 38 | 39 | ## Squirrel 40 | 41 | - 134 42 | 43 | ## Wisp 44 | 45 | - 10045 46 | 47 | ## Toad 48 | 49 | - 901 50 | 51 | ## Dwarf Males 52 | 53 | - 19174 54 | 55 | ## Dwarf Females 56 | 57 | - 58 | 59 | ## Gnome Males 60 | 61 | - 62 | 63 | ## Gnome Females 64 | 65 | - 66 | 67 | ## Draenei Males 68 | 69 | - 70 | 71 | ## Draenei Females 72 | 73 | - 74 | 75 | ## Orc Males 76 | 77 | - 78 | 79 | ## Orc Females 80 | 81 | - 82 | 83 | ## Undead Males 84 | 85 | - 86 | 87 | ## Undead Females 88 | 89 | - 90 | 91 | ## Tauren Males 92 | 93 | - 94 | 95 | ## Tauren Males 96 | 97 | - 98 | 99 | ## Troll Females 100 | 101 | - 102 | 103 | ## Troll Females 104 | 105 | - 106 | 107 | ## Blood Elf Females 108 | 109 | - 110 | 111 | ## Blood Elf Females 112 | 113 | - 114 | -------------------------------------------------------------------------------- /scripts/azerothcore_source.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "" 4 | echo "#########################################################" 5 | echo "# AzerothCore " 6 | echo "#########################################################" 7 | echo "" 8 | 9 | source scripts/functions.sh 10 | if [ "$1" = "" ]; then error "no configuration file passed"; else source $1; fi 11 | 12 | # Create the directory everything will go into 13 | mkdir -p "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/etc" || error "failed to create etc/ directory" 14 | mkdir -p "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/bin" || error "failed to create bin/ directory" 15 | 16 | # Clone AzerothCore 17 | if [ -d "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SOURCE_DIR}" ]; 18 | then 19 | info "AzerothCore repository already pulled. Updating..." 20 | cd "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SOURCE_DIR}" 21 | git pull || error "failed to git pull AzerothCore repository" 22 | cd $WHERE_WAS_I 23 | else 24 | git clone https://github.com/azerothcore/azerothcore-wotlk.git \ 25 | --branch $AZEROTHCORE_SOURCE_BRANCH \ 26 | --single-branch \ 27 | --depth 1 \ 28 | "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SOURCE_DIR}" \ 29 | || error "failed to clone AzerothCore" 30 | fi 31 | 32 | cd $WHERE_WAS_I -------------------------------------------------------------------------------- /scripts/os.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "" 4 | echo "#########################################################" 5 | echo "# Base OS updates and package installation." 6 | echo "#########################################################" 7 | echo "" 8 | 9 | source scripts/functions.sh 10 | if [ "$1" = "" ]; then error "no configuration file passed"; else source $1; fi 11 | 12 | # Update OS packages 13 | sudo apt update || error "package metadata update failed" 14 | 15 | # Install the required packages (requires root) 16 | # (This is the MariaDB set of packages) 17 | # This disables dumb TUI popups, preventing automated installs 18 | sudo DEBIAN_FRONTEND=noninteractive \ 19 | apt install -yq \ 20 | git \ 21 | cmake \ 22 | make \ 23 | gcc \ 24 | g++ \ 25 | clang \ 26 | libssl-dev \ 27 | libbz2-dev \ 28 | libreadline-dev \ 29 | libncurses-dev \ 30 | libboost-all-dev \ 31 | mariadb-server \ 32 | mariadb-client \ 33 | libmariadb-dev \ 34 | libmariadb-dev-compat \ 35 | unzip \ 36 | ufw \ 37 | || error "AzerothCore dependency installation failed" 38 | 39 | # Install extra nice to have 40 | sudo DEBIAN_FRONTEND=noninteractive apt install -yq fail2ban lsof net-tools || warning "Non-mandatory package installation failed" 41 | 42 | # A bit of clean up 43 | sudo DEBIAN_FRONTEND=noninteractive apt autoremove || warning "clean stage failed" 44 | 45 | cd $WHERE_WAS_I -------------------------------------------------------------------------------- /docs/entry-ids.md: -------------------------------------------------------------------------------- 1 | # Entry IDs 2 | 3 | These are the entry IDs I use. I categorise them here so I don't get overlapping or conflict, which can be hard to detect, because you might wipe out an NPC no one knows about 500kms away. 4 | 5 | ## Quests 6 | 7 | - Start: `9100000` 8 | - Generic: `9110000` 9 | - The Argent Dawn: `9111000` 10 | - Bloodsail Buccaneers: `9112000` 11 | - Cenarion Circle: `9113000` 12 | - Hydraxian Waterlords: `9114000` 13 | - Thorium Brotherhood: `9115000` 14 | - Timbermaw Hold: `9116000` 15 | 16 | ## NPCs 17 | 18 | - Start: `9200000` 19 | - Generic: `9210000` 20 | - The Argent Dawn: `9211000` 21 | - Bloodsail Buccaneers: `9212000` 22 | - Cenarion Circle: `9213000` 23 | - Hydraxian Waterlords: `9214000` 24 | - Thorium Brotherhood: `9215000` 25 | - Timbermaw Hold: `9216000` 26 | - Booty Bay: `9217000` 27 | 28 | ## Items 29 | 30 | - Start: `9300000` 31 | - Generic: `9310000` 32 | - The Argent Dawn: `9311000` 33 | - Bloodsail Buccaneers: `9312000` 34 | - Cenarion Circle: `9313000` 35 | - Hydraxian Waterlords: `9314000` 36 | - Thorium Brotherhood: `9315000` 37 | - Timbermaw Hold: `9316000` 38 | 39 | ## Game Objects 40 | 41 | - Start: `9400000` 42 | - Generic: `9410000` 43 | - The Argent Dawn: `9411000` 44 | - Bloodsail Buccaneers: `9412000` 45 | - Cenarion Circle: `9413000` 46 | - Hydraxian Waterlords: `9414000` 47 | - Thorium Brotherhood: `9415000` 48 | - Timbermaw Hold: `9416000` 49 | - Booty Bay: `9417000` 50 | -------------------------------------------------------------------------------- /scripts/firewall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "" 4 | echo "#########################################################" 5 | echo "# Firewall" 6 | echo "#########################################################" 7 | echo "" 8 | 9 | source scripts/functions.sh 10 | if [ "$1" = "" ]; then error "no configuration file passed"; else source $1; fi 11 | 12 | sudo ufw default allow outgoing || error "allowing outgoing network traffic failed" 13 | sudo ufw allow from 0.0.0.0/0 to any port 22 || error "allowing SSH network traffic failed" 14 | sudo ufw allow from 0.0.0.0/0 to any port 3724 || error "allowing Auth Server network traffic failed" 15 | 16 | # This rule is more dynamic as you can run multiple worlds 17 | # across multiple ports, but the authserver (above) only 18 | # runs once 19 | sudo ufw allow from 0.0.0.0/0 to any port $AZEROTHCORE_SERVER_BIND_PORT || error "allowing World Server port ${AZEROTHCORE_SERVER_BIND_PORT} failed" 20 | 21 | # The database must be kept closed off from the world 22 | sudo ufw allow from $AZEROTHCORE_SERVER_BIND_IP to any port 3306 || error "failed to restrict port 3306 to ${AZEROTHCORE_SERVER_BIND_IP}" 23 | sudo ufw allow from 127.0.0.1 to any port 3306 || error "failed to restrict port 3306 to 127.0.0.1" 24 | 25 | # Block absolutely everything else 26 | sudo ufw default deny incoming || error "failed to set default deny policy on incoming traffic" 27 | sudo ufw --force enable || error "failed to (forcefully) enable ufw" 28 | 29 | cd $WHERE_WAS_I -------------------------------------------------------------------------------- /scripts/backup-database.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "" 4 | echo "#########################################################" 5 | echo "# Backup Database(s)" 6 | echo "#########################################################" 7 | echo "" 8 | 9 | source scripts/functions.sh 10 | if [ "$1" = "" ]; then error "Did you forget to provide a configuration file?"; else source $1; fi 11 | 12 | BACKUP_TO="${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/backups/${AZEROTHCORE_SERVER_DIR}/database" 13 | NOW=$(date '+%Y%m%d_%H%M%S') 14 | 15 | mkdir -p "${BACKUP_TO}/${AZEROTHCORE_WORLD_DATABASE}/" || error "failed to create world database backup directory" 16 | mkdir -p "${BACKUP_TO}/${AZEROTHCORE_AUTH_DATABASE}/" || error "failed to create auth database backup directory" 17 | mkdir -p "${BACKUP_TO}/${AZEROTHCORE_CHARACTERS_DATABASE}/" || error "failed to create characters database backup directory" 18 | 19 | mysqldump -u acore $AZEROTHCORE_WORLD_DATABASE > "${BACKUP_TO}/${AZEROTHCORE_WORLD_DATABASE}/${NOW}.sql" \ 20 | || error "backing up of '${AZEROTHCORE_WORLD_DATABASE}' database failed" 21 | 22 | mysqldump -u acore $AZEROTHCORE_AUTH_DATABASE > "${BACKUP_TO}/${AZEROTHCORE_AUTH_DATABASE}/${NOW}.sql" \ 23 | || error "backing up of '${AZEROTHCORE_AUTH_DATABASE}' database failed" 24 | 25 | mysqldump -u acore $AZEROTHCORE_CHARACTERS_DATABASE > "${BACKUP_TO}/${AZEROTHCORE_CHARACTERS_DATABASE}/${NOW}.sql" \ 26 | || error "backing up of '${AZEROTHCORE_CHARACTERS_DATABASE}' database failed" 27 | -------------------------------------------------------------------------------- /scripts/azerothcore_modules.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "" 4 | echo "#########################################################" 5 | echo "# AzerothCore - Modules" 6 | echo "#########################################################" 7 | echo "" 8 | 9 | source scripts/functions.sh 10 | if [ "$1" = "" ]; then error "Did you forget to provide a configuration file?"; else source $1; fi 11 | 12 | function module { 13 | if [ -e "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SOURCE_DIR}/modules/${1}" ] 14 | then 15 | warning "skipping ${1} as directory exists" 16 | else 17 | git clone \ 18 | --depth 1 \ 19 | --branch $2 \ 20 | $3 \ 21 | "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SOURCE_DIR}/modules/${1}" \ 22 | || error "failed to clone module ${3}" 23 | fi 24 | } 25 | 26 | function patch { 27 | cd "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SOURCE_DIR}" || error "failed to change into source directory" 28 | git apply "${1}" || error "failed to git apply patch to core" 29 | cd $WHERE_WAS_I 30 | } 31 | 32 | function sql { 33 | mysql -u acore $1 < "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SOURCE_DIR}/${2}" || erro "failed to import SQL file" 34 | } 35 | 36 | function sql_raw { 37 | mysql -u acore $1 -e "${1}" || error "failed to execute raw SQL" 38 | } 39 | 40 | for module in "${AZEROTHCORE_MODULES[@]}"; do eval $module; done 41 | cd $WHERE_WAS_I 42 | -------------------------------------------------------------------------------- /scripts/azerothcore_data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "" 4 | echo "#########################################################" 5 | echo "# AzerothCore - Data Files" 6 | echo "#########################################################" 7 | echo "" 8 | 9 | source scripts/functions.sh 10 | if [ "$1" = "" ]; then error "Did you forget to provide a configuration file?"; else source $1; fi 11 | 12 | cd $WHERE_WAS_I 13 | 14 | # Setup directory for world/client data files 15 | mkdir -p "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/bin/data" || error "failed to create bin/data directory" 16 | 17 | # We download the v16 maps, mmaps, VMOs, cameras, etc. 18 | if [ ! -f "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/bin/data/v16.zip" ]; 19 | then 20 | # Sometimes people cancel this download partway through, and there's a rough 21 | # .zip file that breaks everything, so this clears it 22 | rm -f data.zip* 23 | 24 | wget https://github.com/wowgaming/client-data/releases/download/v16/data.zip || error "failed to wget data files from GitHub" 25 | mv data.zip "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/bin/data/v16.zip" || failed "failed to move data files to installation directory" 26 | 27 | # Extract them to the server's data directory 28 | unzip "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/bin/data/v16.zip" \ 29 | -d "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/bin/data" \ 30 | || error "failed to unzip data files in installation directory" 31 | else 32 | warning "skipping data file download and extraction as everything is in place(?)" 33 | fi 34 | 35 | cd $WHERE_WAS_I -------------------------------------------------------------------------------- /scripts/azerothcore_compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "" 4 | echo "#########################################################" 5 | echo "# AzerothCore - Compile" 6 | echo "#########################################################" 7 | echo "" 8 | 9 | source scripts/functions.sh 10 | if [ "$1" = "" ]; then error "Did you forget to provide a configuration file?"; else source $1; fi 11 | 12 | if [ -e "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/bin/worldserver" ]; 13 | then 14 | info "the worldserver binary is already in place; compiling not needed(?)" 15 | return 16 | fi 17 | 18 | if [ -e "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/bin/authserver" ]; 19 | then 20 | info "the authserver binary is already in place; compiling not needed(?)" 21 | return 22 | fi 23 | 24 | # Setup build environment 25 | cd "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SOURCE_DIR}" || error "failed to change to source directory" 26 | mkdir -p build/ || error "failed to create build directory" 27 | cd build 28 | 29 | # cmake the configuration, ready for compilation 30 | cmake ../ -DCMAKE_INSTALL_PREFIX="${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/" \ 31 | -DCMAKE_C_COMPILER=/usr/bin/clang \ 32 | -DCMAKE_CXX_COMPILER=/usr/bin/clang++ \ 33 | -DWITH_WARNINGS=1 \ 34 | -DTOOLS_BUILD=all \ 35 | -DSCRIPTS=static \ 36 | -DMODULES=static \ 37 | || error "cmake failed to process project" 38 | 39 | # make/compile our project and install it to AZEROTHCORE_SERVER_DIR 40 | make -j $(nproc --all) || error "failed to compile core" 41 | make install || error "failed to install compiled core" 42 | 43 | cd $WHERE_WAS_I -------------------------------------------------------------------------------- /scripts/azerothcore_worldserver_run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "" 4 | echo "#########################################################" 5 | echo "# First run of World Server" 6 | echo "#########################################################" 7 | echo "" 8 | 9 | cd $WHERE_WAS_I 10 | 11 | mkdir -p "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/etc/modules/" 12 | cp configurations/modules/*.conf.dist "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/etc/modules/" 13 | 14 | # Now we need to run the worldserver so that the database is populated 15 | echo "" 16 | echo "====================================================================================" 17 | echo "" 18 | echo "World Server is about to be run to initialize DB and accounts." 19 | echo "When its finished running, and you see the AC> prompt, create whatever accounts" 20 | echo "you need NOW, then Contrl+C so the script can finalise the setup preocess." 21 | echo "" 22 | echo "See here for creating account: https://www.azerothcore.org/wiki/creating-accounts" 23 | echo "" 24 | echo "====================================================================================" 25 | echo "" 26 | 27 | # Shutdown an existing server, if applicable 28 | sudo systemctl stop azerothcore-world-server.service 29 | 30 | # Make the Console is enabled first 31 | # sed -i 's/Console.Enable = 0/Console.Enable = 1/g' "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/etc/worldserver.conf" 32 | 33 | read -p "Press any key to run worldserver..." 34 | cd "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/bin/" 35 | ./worldserver 36 | 37 | # I disable the console at this point because I'm running the service using systemd. 38 | sed -i 's/Console.Enable = 1/Console.Enable = 0/g' "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/etc/worldserver.conf" 39 | cd $WHERE_WAS_I -------------------------------------------------------------------------------- /sql/auth/a-00-initial-database-setup-gm-account.sql: -------------------------------------------------------------------------------- 1 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 2 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 3 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 4 | /*!40101 SET NAMES utf8mb4 */; 5 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 6 | /*!40103 SET TIME_ZONE='+00:00' */; 7 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 8 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 9 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 10 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 11 | 12 | -- Creates a `GM_MASTER` user with the password `badpassword` 13 | -- This GM account is level 3, so complete control. It should 14 | -- have its password changed completely. More ideally, the whole 15 | -- account should be deleted and a new one created after the 16 | -- server has been tested and goes into production. 17 | 18 | INSERT INTO `account` ( 19 | `id`, 20 | `username`, 21 | `salt`, 22 | `verifier`, 23 | `session_key`, 24 | `totp_secret`, 25 | `email`, 26 | `reg_mail`, 27 | `joindate`, 28 | `last_ip`, 29 | `last_attempt_ip`, 30 | `failed_logins`, 31 | `locked`, 32 | `lock_country`, 33 | `last_login`, `online`, `expansion`, `mutetime`, `mutereason`, `muteby`, `locale`, `os`, `recruiter`, `totaltime`) 34 | VALUES ( 35 | 1, 36 | 'ROOT', 37 | _binary 0x861dddc97fdca6528091443576d5cca20d5709e4d498660941160fd75810a736, 38 | _binary 0x865c67c963b0d81f0c9ff6821ce2a331381522aed16b0f3a473f84818fcfde2a, 39 | _binary 0x9da1ce8533959e11e330955b46819c9088acdffd4decaf272f98f1f05f8647a13a6da56eedf9095c, 40 | NULL, 41 | '', 42 | '', 43 | '2023-11-15 21:34:04', 44 | '127.0.0.1', 45 | '127.0.0.1', 46 | 0, 47 | 0, 48 | '00', 49 | '2024-02-14 23:26:08', 50 | 0, 51 | 2, 52 | 0, 53 | '', 54 | '', 55 | 0, 56 | 'Win', 57 | 0, 58 | 35399 59 | ); 60 | 61 | INSERT INTO `account_access` (id, gmlevel, RealmID, comment) VALUES ( 62 | 1, 3, -1, "Default GM account" 63 | ); -------------------------------------------------------------------------------- /scripts/import_sql.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "" 4 | echo "#########################################################" 5 | echo "# Import Custom SQL" 6 | echo "#########################################################" 7 | echo "" 8 | 9 | source scripts/functions.sh 10 | if [ "$1" = "" ]; then error "Did you forget to provide a configuration file?"; else source $1; fi 11 | 12 | cd $WHERE_WAS_I 13 | IMPORT_LOCK_PATH="${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/locks" 14 | 15 | function import_auth() { 16 | LOCK_FILE="${IMPORT_LOCK_PATH}/sqlimport.auth.$(basename $1).lock" 17 | if [ -e $LOCK_FILE ]; 18 | then 19 | warning "file $1 already imported" 20 | return 21 | fi 22 | 23 | info "SQL importing: $1" 24 | mysql -u acore $AZEROTHCORE_AUTH_DATABASE < $1 || error "SQL import of '${1}' failed" 25 | touch $LOCK_FILE || error "failed to create lockfile" 26 | } 27 | 28 | function import_world() { 29 | LOCK_FILE="${IMPORT_LOCK_PATH}/sqlimport.world.$(basename $1).lock" 30 | if [ -e $LOCK_FILE ]; 31 | then 32 | warning "file $1 already imported" 33 | return 34 | fi 35 | 36 | info "SQL importing: $1" 37 | mysql -u acore $AZEROTHCORE_WORLD_DATABASE < $1 || error "SQL import of '${1}' failed" 38 | touch $LOCK_FILE || error "failed to create lockfile" 39 | } 40 | 41 | # We _always_ do a backup of the database before we 42 | # import _any_ SQL 43 | source scripts/backup-database.sh $1 44 | 45 | # These are manually written SQL files and are not 46 | # directly written to by Python or any other scripts 47 | import_auth "sql/auth/a-00-initial-database-setup-gm-account.sql" 48 | import_world "sql/world/a-01-quality-of-life.sql" 49 | import_world "sql/world/a-02-starting-mount-accessiblity.sql" 50 | import_world "sql/world/a-03-better-herb-spawns.sql" 51 | import_world "sql/world/a-04-better-mining-spawns.sql" 52 | import_world "sql/world/a-05-various-spawnable-objects.sql" 53 | import_world "sql/world/a-06-various-spawnable-npcs.sql" 54 | 55 | # Now we automatically import any SQL files included by 56 | # the server adminstrator.We ignore anything that starts 57 | # with "a-*", as that's handled above. 58 | for sqlfile in $(ls sql/auth/*.sql | grep -v 'a-*'); do import_auth $sqlfile; done 59 | for sqlfile in $(ls sql/world/*.sql | grep -v 'a-*'); do import_world $sqlfile; done 60 | 61 | cd $WHERE_WAS_I -------------------------------------------------------------------------------- /scripts/systemd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "" 4 | echo "#########################################################" 5 | echo "# Systemd." 6 | echo "#########################################################" 7 | echo "" 8 | 9 | source scripts/functions.sh 10 | if [ "$1" = "" ]; then error "no configuration file passed"; else source $1; fi 11 | 12 | cd $WHERE_WAS_I 13 | 14 | # Create systemd .service files 15 | cat < "${AZEROTHCORE_SERVER_DIR}-world.service" 16 | [Unit] 17 | Description=AzerothCore 3.3.5a World Server 18 | After=network.target 19 | 20 | [Service] 21 | User=superman 22 | Group=superman 23 | PrivateTmp=true 24 | Type=simple 25 | PIDFile=/run/azerothcore/worldserver.pid 26 | WorkingDirectory=${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/bin/ 27 | ExecStart=${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/bin/worldserver 28 | 29 | [Install] 30 | WantedBy=multi-user.target 31 | EOF 32 | 33 | cat < "${AZEROTHCORE_SERVER_DIR}-auth.service" 34 | [Unit] 35 | Description=AzerothCore 3.3.5a Auth Server 36 | After=network.target 37 | 38 | [Service] 39 | User=superman 40 | Group=superman 41 | PrivateTmp=true 42 | Type=simple 43 | PIDFile=/run/azerothcore/authserver.pid 44 | WorkingDirectory=${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/bin/ 45 | ExecStart=${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/bin/authserver 46 | 47 | [Install] 48 | WantedBy=multi-user.target 49 | EOF 50 | 51 | # Move the service files into place 52 | sudo mv ${AZEROTHCORE_SERVER_DIR}-world.service /etc/systemd/system/${AZEROTHCORE_SERVER_DIR}-world.service \ 53 | || error "failed to move worldserver .service file into place" 54 | 55 | sudo mv ${AZEROTHCORE_SERVER_DIR}-auth.service /etc/systemd/system/${AZEROTHCORE_SERVER_DIR}-auth.service \ 56 | || error "failed to move authserver .service file into place" 57 | 58 | # Enable and start our services 59 | sudo systemctl enable ${AZEROTHCORE_SERVER_DIR}-auth.service \ 60 | || error "failed to enable authserver service" 61 | 62 | sudo systemctl start ${AZEROTHCORE_SERVER_DIR}-auth.service \ 63 | || error "failed to start authserver service" 64 | 65 | sudo systemctl enable ${AZEROTHCORE_SERVER_DIR}-world.service \ 66 | || error "failed to start worldserver service" 67 | 68 | sudo systemctl start ${AZEROTHCORE_SERVER_DIR}-world.service \ 69 | || error "failed to start worldserver service" 70 | 71 | cd $WHERE_WAS_I 72 | -------------------------------------------------------------------------------- /kill-everything.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "" 4 | echo "#########################################################" 5 | echo "# KILL EVERYTHING!" 6 | echo "#########################################################" 7 | echo "" 8 | 9 | source scripts/functions.sh 10 | if [ "$1" = "" ]; then error "no configuration file passed"; else source $1; fi 11 | 12 | echo "!!! This script is _dangerous_ !!!" 13 | echo "!!! It will KILL your entire Azeroth Core setup !!!" 14 | echo "!!! You have been warned !!!" 15 | echo "" 16 | echo "NOW is your chance to bail: hit Control + C if running this script was a mistake..." 17 | read -p "(or press any key to continue...)" -n1 -s 18 | 19 | # Just so the sudo prompts get a new line. Avoids confusion. 20 | echo "" 21 | 22 | # Stop services 23 | sudo systemctl disable ${AZEROTHCORE_SERVER_DIR}-auth.service || warning "failed to disable authserver service" 24 | sudo systemctl disable ${AZEROTHCORE_SERVER_DIR}-world.service || warning "failed to disable worldserver service" 25 | sudo systemctl stop ${AZEROTHCORE_SERVER_DIR}-auth.service || warning "failed to stop authserver service" 26 | sudo systemctl stop ${AZEROTHCORE_SERVER_DIR}-world.service || warning "failed to stop worldserver service" 27 | 28 | sudo rm -f /etc/systemd/system/${AZEROTHCORE_SERVER_DIR}-auth.service || warning "failed to delete ${AZEROTHCORE_SERVER_DIR}-auth.service file" 29 | sudo rm -f /etc/systemd/system/${AZEROTHCORE_SERVER_DIR}-world.service || warning "failed to delete ${AZEROTHCORE_SERVER_DIR}-world.service file" 30 | 31 | # Backup DB 32 | source scripts/backup-database.sh $1 33 | 34 | # Drop ALL tables AFTER a backup... 35 | mysql -u acore mysql -e "DROP DATABASE $AZEROTHCORE_WORLD_DATABASE;" || warning "failed to drop $AZEROTHCORE_WORLD_DATABASE" 36 | mysql -u acore mysql -e "DROP DATABASE $AZEROTHCORE_AUTH_DATABASE;" || warning "failed to drop $AZEROTHCORE_AUTH_DATABASE" 37 | mysql -u acore mysql -e "DROP DATABASE $AZEROTHCORE_CHARACTERS_DATABASE;" || warning "failed to drop $AZEROTHCORE_CHARACTERS_DATABASE" 38 | 39 | # Stop the DB 40 | sudo systemctl stop mariadb || warning "failed to stop MariaDB" 41 | 42 | # Now KILL __ALL__ AzerothCore files on disk 43 | rm -rf "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}" || warning "failed to delete server installation directory" 44 | rm -rf "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SOURCE_DIR}" || warning "failed to delete AzerothCore source directory" 45 | 46 | info "done" 47 | -------------------------------------------------------------------------------- /scripts/azerothcore_configs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "" 4 | echo "#########################################################" 5 | echo "# Server Configuration Files" 6 | echo "#########################################################" 7 | echo "" 8 | 9 | source scripts/functions.sh 10 | if [ "$1" = "" ]; then error "Did you forget to provide a configuration file?"; else source $1; fi 11 | 12 | cd $WHERE_WAS_I 13 | 14 | ETC_PATH="${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/etc" 15 | 16 | # Check for the "purge" subcommand being passed to the script 17 | if [ "$2" = "purge" ]; 18 | then 19 | info "purging existing configurations..." 20 | NOW=$(date '+%Y%m%d_%H%M%S') 21 | cp "${ETC_PATH}/worldserver.conf" "${ETC_PATH}/worldserver.conf.backup.${NOW}" || error "failed to backup world configuration file" 22 | cp "${ETC_PATH}/authserver.conf" "${ETC_PATH}/authserver.conf.backup.${NOW}" || error "failed to backup auth configuration file" 23 | rm -f "${ETC_PATH}/worldserver.conf" 24 | rm -f "${ETC_PATH}/authserver.conf" 25 | fi 26 | 27 | # Move our configurations in place 28 | # ... but only if they don't already exist, because there might be 29 | # custom changes we'll end up overriding... 30 | if [ ! -f "${ETC_PATH}/worldserver.conf" ]; 31 | then 32 | COPY_TO="${ETC_PATH}/worldserver.conf" 33 | info "copying worldserver.main.conf to $COPY_TO" 34 | cp configurations/worldserver.main.conf $COPY_TO || error "failed to copy worldserver configuration file" 35 | 36 | info "updating $COPY_TO..." 37 | 38 | # Don't be a smart arse and replace these with 'info' calls 39 | echo "BindIP = $AZEROTHCORE_SERVER_BIND_IP" >> "${ETC_PATH}/worldserver.conf" || error "failed to update BindIP" 40 | echo "WorldServerPort = $AZEROTHCORE_SERVER_BIND_PORT" >> "${ETC_PATH}/worldserver.conf" || error "failed to update WorldServerPort" 41 | echo "WorldDatabaseInfo = \"${MARIADB_SERVER_IP};${MARIADB_SERVER_PORT};acore;acore;$AZEROTHCORE_WORLD_DATABASE\"" >> "${ETC_PATH}/worldserver.conf" || error "failed to update WorldDatabaseInfo" 42 | echo "LoginDatabaseInfo = \"${MARIADB_SERVER_IP};${MARIADB_SERVER_PORT};acore;acore;$AZEROTHCORE_AUTH_DATABASE\"" >> "${ETC_PATH}/worldserver.conf" || error "failed to update LoginDatabaseInfo" 43 | echo "CharacterDatabaseInfo = \"${MARIADB_SERVER_IP};${MARIADB_SERVER_PORT};acore;acore;$AZEROTHCORE_CHARACTERS_DATABASE\"" >> "${ETC_PATH}/worldserver.conf" || error "failed to update CharacterDatabaseInfo" 44 | else 45 | info "leaving existing ${ETC_PATH}/worldserver.conf alone" 46 | fi 47 | 48 | if [ ! -f "${ETC_PATH}/authserver.conf" ]; 49 | then 50 | COPY_TO="${ETC_PATH}/authserver.conf" 51 | info "copying authserver.conf to $COPY_TO" 52 | cp configurations/authserver.conf $COPY_TO 53 | 54 | info "Updating $COPY_TO..." 55 | 56 | # Don't be a smart arse and replace these with 'info' calls 57 | echo "BindIP = $AZEROTHCORE_SERVER_BIND_IP" >> $COPY_TO || error "failed to update BindIP" 58 | echo "LoginDatabaseInfo = \"${MARIADB_SERVER_IP};${MARIADB_SERVER_PORT};acore;acore;$AZEROTHCORE_AUTH_DATABASE\"" >> $COPY_TO || error "failed to update LoginDatabaseInfo" 59 | else 60 | info "leaving existing ${ETC_PATH}/authserver.conf alone" 61 | fi 62 | 63 | cd $WHERE_WAS_I -------------------------------------------------------------------------------- /sql/world/a-06-various-spawnable-npcs.sql: -------------------------------------------------------------------------------- 1 | 2 | -- this SQL creates NPCs we can use in quests and more. 3 | -- 4 | -- These are simply made to "exist" and be available for future use. 5 | -- The items aren't made visible by these SQL statements. 6 | 7 | -- SET @BaseEntry := 960000; 8 | 9 | -- SET 10 | -- @Entry := @BaseEntry+1, 11 | -- @ModelID1 := 4845, 12 | -- @ModelID2 := 4846, 13 | -- @ModelID3 := 4847, 14 | -- @ModelID4 := 4848, 15 | -- @Name := "Elirenna", 16 | -- @Subname := NULL, 17 | -- @MinLevel := 40, 18 | -- @MaxLevel := 43, 19 | -- @Faction := 79, 20 | -- @NPCFlag := 2, 21 | -- @Rank := 0, 22 | -- @Type := 7, -- Human 23 | -- @RunSpeed := 1.14286; 24 | -- DELETE FROM `creature_template` WHERE (`entry` = @Entry); 25 | -- INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `modelid1`, `modelid2`, `modelid3`, `modelid4`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES 26 | -- (@Entry, 0, 0, 0, 0, 0, @ModelID1, @ModelID2, @ModelID3, @ModelID4, @Name, NULL, NULL, @MinLevel, @MaxLevel, 0, @Faction, 35, 0, 1, 1.14286, 1, 1, 20, 1, 0, 0, 1, 2000, 2000, 1, 1, 1, 0, 2048, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 1250, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 12340); 27 | 28 | -- DELETE FROM `creature_template` WHERE (`entry` = 6086); 29 | -- INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `modelid1`, `modelid2`, `modelid3`, `modelid4`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES 30 | -- (@Entry, 0, 0, 0, 0, 0, @ModelID1, @ModelID2, @ModelID3, @ModelID4, @Name, @Subname, NULL, @MinLevel, @MaxLevel, 0, @Faction, @NPCFlag, @Rank, @RunSpeed, 1, 1, 18, 1, 0, 0, 1, 2000, 2000, 1, 1, 1, 0, 2048, 0, 0, 0, 0, 0, 0, 7, 0, 0, 6086, 0, 0, 0, 0, 0, '', 1, 1, 2, 1, 1, 1, 0, 0, 1, 0, 0, 65536, '', 12340); 31 | -------------------------------------------------------------------------------- /config.sh.example: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This is the PUBLIC IP address you want your server to be 4 | # accessible from. 5 | # 6 | # A value of 127.0.0.1 means your local computer ONLY. This 7 | # address cannot be reached from anywhere else, even your 8 | # local network. 9 | # 10 | # If you want to be able to reach your server via 11 | # the PUBLIC INTERNET, then you *must* use an Internet routable 12 | # IP address. This is more complex and requires you to 13 | # understand basic networking concepts like routing and IPv4. 14 | export AZEROTHCORE_SERVER_REMOTE_ENDPOINT="127.0.0.1" 15 | 16 | # This IP address is the LOCAL IP address AzrothCore's 17 | # components will listen for connections on. This (probably) 18 | # Isn't your PUBLIC IP address. It's going to be a value 19 | # like 127.0.0.1, 192.168.88.X, or 0.0.0.0. 20 | # 21 | # A value of 127.0.0.1 means your local computer ONLY. This 22 | # address cannot be reached from anywhere else, even your 23 | # local network. 24 | # 25 | # A value of 0.0.0.0 means the server will bind to ANY and 26 | # ALL IP addresses on your system, including 127.0.0.1. This 27 | # is ideal if you want to be able to access the server from 28 | # your local PC and other systems on the local area network. 29 | # 30 | # If you have specific IP attached to your computer that you 31 | # want to use, like "192.168.88.10", then use that. This 32 | # means local clients must set their realmlist IPs to that 33 | # address (or DNS that resolve to it.) 34 | export AZEROTHCORE_SERVER_BIND_IP="127.0.0.1" 35 | 36 | # This defines the parent directory that will contain everything 37 | # that's built, installed, and more. The end result is a path 38 | # like "/home/mike/azerothcore_servers/...". You can change 39 | # this if you don't like that path name. 40 | export AZEROTHCORE_INSTALL_PARENT_DIR=azerothcore_servers 41 | 42 | # !!! 43 | # You can probably ignore everything below this point 44 | # !!! 45 | 46 | export AZEROTHCORE_SOURCE_DIR=azerothcore 47 | export AZEROTHCORE_SOURCE_BRANCH=master 48 | export AZEROTHCORE_SERVER_DIR=azerothcore-server 49 | export AZEROTHCORE_SERVER_BACKUPS_DIR=azerothcore-server-backups 50 | export DATABASE_LOCK_DIR="${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/locks/" 51 | export AZEROTHCORE_SERVER_REALM_NAME=AzerothCore 52 | export AZEROTHCORE_SERVER_BIND_PORT=8085 53 | export AZEROTHCORE_SERVER_LOCAL_SUBNETMASK=255.255.255.0 54 | export AZEROTHCORE_AUTH_DATABASE="acore_auth" 55 | export AZEROTHCORE_WORLD_DATABASE="acore_world" 56 | export AZEROTHCORE_CHARACTERS_DATABASE="acore_characters" 57 | export MARIADB_SERVER_IP=127.0.0.1 58 | export MARIADB_SERVER_PORT=3306 59 | 60 | # Modules 61 | export AZEROTHCORE_MODULES=( 62 | "module mod-eluna master https://github.com/azerothcore/mod-eluna.git" 63 | "module mod-autobalance master https://github.com/azerothcore/mod-autobalance.git" 64 | "module mod-solo-lfg master https://github.com/azerothcore/mod-solo-lfg.git" 65 | ) 66 | 67 | # Behaviour flags 68 | export DB_CREATE=true 69 | export DB_MANAGE_AUTH=true 70 | export DB_MANAGE_WORLD=true 71 | export DB_MANAGE_CHARACTERS=true 72 | export RUN_OS=true 73 | export RUN_FIREWALL=true 74 | export RUN_AZEROTHCORE_SOURCE=true 75 | export RUN_AZEROTHCORE_DATABASE=true 76 | export RUN_AZEROTHCORE_DATA=true 77 | export RUN_AZEROTHCORE_MODULES=true 78 | export RUN_AZEROTHCORE_COMPILE=true 79 | export RUN_AZEROTHCORE_CONFIGS=true 80 | export RUN_AZEROTHCORE_WORLDSERVER_RUN=true 81 | export RUN_IMPORT_SQL=true 82 | export RUN_SYSTEMD=true 83 | 84 | # Internal variables 85 | export WHERE_WAS_I=$(pwd) -------------------------------------------------------------------------------- /config.ptr.sh.example: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This is the PUBLIC IP address you want your server to be 4 | # accessible from. 5 | # 6 | # A value of 127.0.0.1 means your local computer ONLY. This 7 | # address cannot be reached from anywhere else, even your 8 | # local network. 9 | # 10 | # If you want to be able to reach your server via 11 | # the PUBLIC INTERNET, then you *must* use an Internet routable 12 | # IP address. This is more complex and requires you to 13 | # understand basic networking concepts like routing and IPv4. 14 | export AZEROTHCORE_SERVER_REMOTE_ENDPOINT="127.0.0.1" 15 | 16 | # This IP address is the LOCAL IP address AzrothCore's 17 | # components will listen for connections on. This (probably) 18 | # Isn't your PUBLIC IP address. It's going to be a value 19 | # like 127.0.0.1, 192.168.88.X, or 0.0.0.0. 20 | # 21 | # A value of 127.0.0.1 means your local computer ONLY. This 22 | # address cannot be reached from anywhere else, even your 23 | # local network. 24 | # 25 | # A value of 0.0.0.0 means the server will bind to ANY and 26 | # ALL IP addresses on your system, including 127.0.0.1. This 27 | # is ideal if you want to be able to access the server from 28 | # your local PC and other systems on the local area network. 29 | # 30 | # If you have specific IP attached to your computer that you 31 | # want to use, like "192.168.88.10", then use that. This 32 | # means local clients must set their realmlist IPs to that 33 | # address (or DNS that resolve to it.) 34 | export AZEROTHCORE_SERVER_BIND_IP="127.0.0.1" 35 | 36 | # This defines the parent directory that will contain everything 37 | # that's built, installed, and more. The end result is a path 38 | # like "/home/mike/azerothcore_servers/...". You can change 39 | # this if you don't like that path name. 40 | export AZEROTHCORE_INSTALL_PARENT_DIR=azerothcore_servers 41 | 42 | # !!! 43 | # You can probably ignore everything below this point 44 | # !!! 45 | 46 | export AZEROTHCORE_SOURCE_DIR="azerothcore-ptr" 47 | export AZEROTHCORE_SOURCE_BRANCH="master" 48 | export AZEROTHCORE_SERVER_DIR="azerothcore-ptr-server" 49 | export AZEROTHCORE_SERVER_BACKUPS_DIR="azerothcore-ptr-server-backups" 50 | export DATABASE_LOCK_DIR="${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SERVER_DIR}/locks/" 51 | export AZEROTHCORE_SERVER_REALM_NAME="AzerothCore PTR" 52 | export AZEROTHCORE_SERVER_BIND_PORT=8086 53 | export AZEROTHCORE_SERVER_LOCAL_SUBNETMASK="255.255.255.0" 54 | export AZEROTHCORE_AUTH_DATABASE="acore_auth" 55 | export AZEROTHCORE_WORLD_DATABASE="acore_world_ptr" 56 | export AZEROTHCORE_CHARACTERS_DATABASE="acore_characters_ptr" 57 | 58 | # Modules 59 | export AZEROTHCORE_MODULES=( 60 | "module mod-eluna master https://github.com/azerothcore/mod-eluna.git" 61 | "module mod-autobalance master https://github.com/azerothcore/mod-autobalance.git" 62 | "module mod-solo-lfg master https://github.com/azerothcore/mod-solo-lfg.git" 63 | ) 64 | 65 | # Behaviour flags 66 | export DB_CREATE=true 67 | export DB_MANAGE_AUTH=false # use existing auth for PTR 68 | export DB_MANAGE_WORLD=true 69 | export DB_MANAGE_CHARACTERS=true 70 | export RUN_OS=false # don't manage on PTR runs 71 | export RUN_FIREWALL=false # don't manage on PTR runs 72 | export RUN_AZEROTHCORE_SOURCE=true 73 | export RUN_AZEROTHCORE_DATABASE=true 74 | export RUN_AZEROTHCORE_DATA=true 75 | export RUN_AZEROTHCORE_MODULES=true 76 | export RUN_AZEROTHCORE_COMPILE=true 77 | export RUN_AZEROTHCORE_CONFIGS=true 78 | export RUN_AZEROTHCORE_WORLDSERVER_RUN=true 79 | export RUN_IMPORT_SQL=true 80 | export RUN_SYSTEMD=true 81 | 82 | # Internal variables 83 | export WHERE_WAS_I=$(pwd) -------------------------------------------------------------------------------- /docs/data.md: -------------------------------------------------------------------------------- 1 | # Data 2 | 3 | We pull a lot of data from a lot of sources. This data is (mostly) used to generate huge amounts of SQL statements, which in turn are used to setup vendors, rare spawns, hunt challenges, and more. This means we can data mine various databases, populate a file, and then have a tonne of SQL generated for us. 4 | 5 | This is how the extra NPCs, mobs, etc., are all managed. 6 | 7 | ## Generating 8 | 9 | ``` 10 | python3 -m venv venv 11 | source venv/bin/activate 12 | pip install -r requirements.txt 13 | python3 generate_sql.py 14 | ``` 15 | 16 | And then you want to update and push (to the server) the resulting `results/*.sql` and import the SQL into the DB. 17 | 18 | ## Items 19 | 20 | Everything is managed inside of `data/entities.yaml` 21 | 22 | ### Generating Data 23 | 24 | We have to data mine the DB to find what we're looking for. Although not the most refined way of working, this SQL will find the Elite NPCs in a dungeon or raid that drop a weapon, armor, or recipe that's blue or better quality: 25 | 26 | You have to change `c.map` to the map of the dungeon you want to data mine. 27 | 28 | ```sql 29 | SET 30 | @SuitableLevel := 45, 31 | @Map := 70; 32 | 33 | SELECT 34 | items.LootItem, 35 | itemtemplate.class, 36 | items.CreatureID, 37 | itemtemplate.subclass, 38 | itemtemplate.quality, 39 | itemtemplate.requiredlevel, 40 | items.CreatureMap, 41 | items.CreatureName 42 | FROM 43 | item_template AS itemtemplate, 44 | ( 45 | SELECT 46 | c.map AS CreatureMap, 47 | ct.entry AS CreatureTemplateEntry, 48 | ct.name as CreatureName, 49 | ct.entry AS CreatureID, 50 | clt.item AS LootItem, 51 | clt.groupid AS LootItemGroupID 52 | 53 | FROM creature AS c 54 | INNER JOIN creature_template AS ct ON ct.entry = c.id1 55 | INNER JOIN creature_loot_template AS clt ON ct.entry = clt.entry 56 | WHERE 57 | -- Map or "instance", like Blackfathom Deeps 58 | -- Can be looked up in instance_template 59 | c.map=@Map AND 60 | 61 | -- Creature's rank is at minimum Elite 62 | -- (Personally not interested in what non-Elites drop) 63 | ct.rank >= 1 64 | ) AS items 65 | WHERE 66 | items.LootItem = itemtemplate.entry AND 67 | 68 | -- Item is at minimum blue quality 69 | itemtemplate.quality >= 3 AND 70 | 71 | -- Item is suitable level 72 | itemtemplate.requiredlevel <= @SuitableLevel AND 73 | 74 | -- I only want weapon, armor, or recipes 75 | itemtemplate.class IN (2, 4, 9) 76 | GROUP BY 77 | items.LootItem 78 | ; 79 | ``` 80 | 81 | ### Vendor Groups 82 | 83 | We have "vendor groups" that make dungeon and raid drops/items accessible for gold, _outside_ of the dungeon/raid itself. This is to faciliate the primary objective of this project: solo WoW game play. 84 | 85 | Each item from each dungeon is assigned a type: 86 | 87 | - `weapon` 88 | - `clothing` 89 | - `other` (such as trinket or ring) 90 | 91 | Then it's assigned one of the following tiers: 92 | 93 | - `tier1a` 94 | - `tier1b` 95 | - `tier2a` 96 | - `tier2b` 97 | - `tier3a` 98 | - `tier3b` 99 | - `tier4a` 100 | - `tier4b` 101 | - `tier5a` 102 | - `tier5b` 103 | - `tier6a` 104 | - `tier6b` 105 | - `tier7a` 106 | - `tier7b` 107 | 108 | These _sort of_ map to level ranges, but not strictly. Each tier is a multipler of some base cost. In our case, the base cost is defined as about `1g 20s`. That is then multiplied by a tier's multiplier to get the vendor price of the item. 109 | 110 | These vendor groups sell items based on the type. 111 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AzerothCore Build Scripts (ACBS) 2 | 3 | *NOTE: this project is a **Work In Progress**. There's a lot of work to be done on this project. It's got basically no instructions at the moment.* 4 | 5 | ACBS is a series of shell scripts (bash) that allow you to easily create an AzerothCore server. This means you can emulate a World of Warcraft 3.3.5a server, allowing 3.3.5a clients to connect to the server and enjoy the game locally or on a private/public network with friends. 6 | 7 | ## Warning! 8 | 9 | These scripts _do not_ replace a well rounded education in Linux, networking, server administration, or cybersecurity. They're simply here to help you get started. It's important to understand that you're putting a complex, potentially vulnerable, piece of software on your computer and/or network that could be exploited by a remote malicous actor. If you put the AzerothCore server on _the publinc Internet_, this fact is 10x more true. 10 | 11 | Play it safe and understand what is happening here. 12 | 13 | ## Also, before you start... 14 | 15 | You should be aware of these facts regarding the network security of your Linux host once you use these scripts: 16 | 17 | 1. This script will open several firewall rules on your server: 18 | 1. `TCP/22` for SSH will be opened to `0.0.0.0/0` 19 | 1. `TCP/8085` for the World Server will be opened to `0.0.0.0/0` 20 | 1. `TCP/3724` for the Auth Server will be opened to `0.0.0.0/0` 21 | 1. Because those ports are opened to `0.0.0.0/0`, if your server is on the public Internet, then __so are those ports__! 22 | 23 | The database is kept operating on the local IP address space, so it's never accessible over the public Internet. 24 | 25 | ## How? 26 | 27 | Executing __all__ scripts has to be done from the root (`.`) of the directory/repository, like this: 28 | 29 | ``` 30 | bash scripts/os.sh 31 | ``` 32 | 33 | Where `` is replaced with a configuration you've copied from `./config.sh.example`. 34 | 35 | ### Requirements 36 | 37 | * Ubuntu 22.04 LTS 38 | 39 | ### Instructions 40 | 41 | To get the AC server up and running with defaults, run the following commands: 42 | 43 | 1. Clone this repository to a Ubuntu 22.04 server: 44 | 1. `git clone ` 45 | 1. Change directory into the cloned repository: 46 | 1. `cd AzerothCore-Build-Scripts` 47 | 1. Copy the `config.sh.example` file to `config.sh` 48 | 1. `cp config.sh.example config.sh` 49 | 1. (_optional step_) Open and edit the `config.sh` file... 50 | 1. ... replacing `AZEROTHCORE_SERVER_REMOTE_ENDPOINT` with your *public* IP address 51 | 1. ... replacing `AZEROTHCORE_SERVER_BIND_IP` with your *private*, *internal* IP address 52 | 1. ... replacing `AZEROTHCORE_INSTALL_PARENT_DIR` with the location to install to under `$HOME` 53 | 1. Run `./setup.sh config.sh` and you should get a working WoW 3.3.5a WotLK server 54 | 55 | The _optional step_ above is only if you want to change how AzerothCore is presented to your local network. If you just want to run it locally, skip that step. 56 | 57 | ## Why? 58 | 59 | [World of Warcraft](https://worldofwarcraft.com/en-gb/) is an awesome game filled with years of content. [It's massive!](https://www.gamermaps.net/world-of-warcraft/map/) But it's not always possible for [everyone to access the game](https://us.forums.blizzard.com/en/wow/t/classic-wow-banned-in-indonesia/1293532); it requires a monthly subscription that some (this author) aren't willing to pay (to Blizzard in its current state); it's published by Activision, who have engaged in [less than ideal employment conditions](https://www.svg.com/703293/the-shady-side-of-activision-blizzard/); and some of us simply enjoy the single-player experience, whilst maintaining the option of playing with other people should that be desirable (it's an MMO after all - built-in coop.) 60 | 61 | With these reasons in mind (and more), I wanted to make it easier to create an AzerthoCore server using Ubuntu Linux. 62 | 63 | ## Support 64 | 65 | If you need support with AzerothCore, then join the [AzerothCore Discord server](https://discord.gg/TZBZ6quZuG) and ask for assistance in the `#support-general`, but make sure to read the rules and notices first. 66 | 67 | If you need assistance with these scripts specifically, then [use my personal Discord instead](https://discord.gg/XS2eVbawxK). 68 | -------------------------------------------------------------------------------- /sql/world/a-05-various-spawnable-objects.sql: -------------------------------------------------------------------------------- 1 | 2 | -- this is about creating gameobjects that are simply for show 3 | -- These objects can be spawned where ever and however we please 4 | -- using dynamic "living world" scripts. 5 | -- 6 | -- These are simply made to "exist" and be available for future use. 7 | -- The items aren't made visible by these SQL statements. 8 | 9 | SET @BaseEntry := 523900; 10 | 11 | SET 12 | @Entry := @BaseEntry, 13 | @DisplayID := 7194, 14 | @Type := 5, 15 | @Name := "Tent"; 16 | DELETE FROM `gameobject_template` WHERE (`entry` = @Entry); 17 | INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `castBarCaption`, `unk1`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `AIName`, `ScriptName`, `VerifiedBuild`) VALUES 18 | (@Entry, @Type, @DisplayID, @Name, '0', '', '', 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0); 19 | 20 | SET 21 | @Entry := @BaseEntry+1, 22 | @DisplayID := 6808, 23 | @Type := 5, 24 | @Name := "Netted Storage Boxes"; 25 | DELETE FROM `gameobject_template` WHERE (`entry` = @Entry); 26 | INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `castBarCaption`, `unk1`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `AIName`, `ScriptName`, `VerifiedBuild`) VALUES 27 | (@Entry, @Type, @DisplayID, @Name, '0', '', '', 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0); 28 | 29 | SET 30 | @Entry := @BaseEntry+2, 31 | @DisplayID := 36, 32 | @Type := 5, 33 | @Name := "Storage Boxes"; 34 | DELETE FROM `gameobject_template` WHERE (`entry` = @Entry); 35 | INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `castBarCaption`, `unk1`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `AIName`, `ScriptName`, `VerifiedBuild`) VALUES 36 | (@Entry, @Type, @DisplayID, @Name, '0', '', '', 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0); 37 | 38 | SET 39 | @Entry := @BaseEntry+3, 40 | @DisplayID := 6362, 41 | @Type := 5, 42 | @Name := "Orc Bench"; 43 | DELETE FROM `gameobject_template` WHERE (`entry` = @Entry); 44 | INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `castBarCaption`, `unk1`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `AIName`, `ScriptName`, `VerifiedBuild`) VALUES 45 | (@Entry, @Type, @DisplayID, @Name, '0', '', '', 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0); 46 | 47 | SET 48 | @Entry := @BaseEntry+4, 49 | @DisplayID := 8421, 50 | @Type := 5, 51 | @Name := "Orc Tent 1"; 52 | DELETE FROM `gameobject_template` WHERE (`entry` = @Entry); 53 | INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `castBarCaption`, `unk1`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `AIName`, `ScriptName`, `VerifiedBuild`) VALUES 54 | (@Entry, @Type, @DisplayID, @Name, '0', '', '', 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0); 55 | 56 | SET 57 | @Entry := @BaseEntry+5, 58 | @DisplayID := 8422, 59 | @Type := 5, 60 | @Name := "Orc Tent 2"; 61 | DELETE FROM `gameobject_template` WHERE (`entry` = @Entry); 62 | INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `castBarCaption`, `unk1`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `AIName`, `ScriptName`, `VerifiedBuild`) VALUES 63 | (@Entry, @Type, @DisplayID, @Name, '0', '', '', 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0); 64 | 65 | SET 66 | @Entry := @BaseEntry+6, 67 | @DisplayID := 8423, 68 | @Type := 5, 69 | @Name := "Orc Tent 3"; 70 | DELETE FROM `gameobject_template` WHERE (`entry` = @Entry); 71 | INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `castBarCaption`, `unk1`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `AIName`, `ScriptName`, `VerifiedBuild`) VALUES 72 | (@Entry, @Type, @DisplayID, @Name, '0', '', '', 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 0); 73 | -------------------------------------------------------------------------------- /scripts/azerothcore_database.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "" 4 | echo "#########################################################" 5 | echo "# Initialise Database" 6 | echo "#########################################################" 7 | echo "" 8 | 9 | source scripts/functions.sh 10 | if [ "$1" = "" ]; then error "Did you forget to provide a configuration file?"; else source $1; fi 11 | 12 | cd $WHERE_WAS_I 13 | 14 | # Move our custom MariaDB 50-server.conf file into place 15 | # then update it 16 | cp configurations/50-server.cnf /tmp/50-server.cnf 17 | echo "bind-address = ${MARIADB_SERVER_IP}" >> /tmp/50-server.cnf 18 | sudo mv /tmp/50-server.cnf /etc/mysql/mariadb.conf.d/50-server.cnf || error "failed to move MariaDB config file" 19 | 20 | # Obviously need to make sure the server is active 21 | sudo systemctl restart mariadb || error "Unable to restart MariaDB." 22 | 23 | # Check for the "purge" subcommand being passed to the script 24 | if [ "$1" = "purge" ]; 25 | then 26 | info "Purging lockfiles to force SQL run..." 27 | rm -f "${DATABASE_LOCK_DIR}/database.*.lock" || error "Unable to remove lock files for purge." 28 | fi 29 | 30 | # Create lock directory if it doesn't already exist. 31 | mkdir -p $DATABASE_LOCK_DIR || error "Unable to create directory for lock files." 32 | 33 | if [ "$DB_CREATE" == true ]; 34 | then 35 | if [ ! -f "${DATABASE_LOCK_DIR}/database.create.lock" ]; 36 | then 37 | info "creating the databases" 38 | touch "${DATABASE_LOCK_DIR}/database.create.lock" || error "Failed to create database lock file." 39 | sudo mysql < "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SOURCE_DIR}/data/sql/create/create_mysql.sql" || error "Unable to import create_mysql.sql." 40 | else 41 | warning "database already created" 42 | fi 43 | fi 44 | 45 | if [ "$DB_MANAGE_AUTH" == true ]; 46 | then 47 | if [ ! -f "${DATABASE_LOCK_DIR}/database.${AZEROTHCORE_AUTH_DATABASE}.lock" ]; 48 | then 49 | info "creating the auth tables" 50 | touch "${DATABASE_LOCK_DIR}/database.${AZEROTHCORE_AUTH_DATABASE}.lock" || error "Failed to create database lock file." 51 | cd "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SOURCE_DIR}/data/sql/base/db_auth/" || error "Failed to change AzerothCore SQL directory." 52 | for sqlfile in $(ls *.sql); 53 | do 54 | sudo mysql $AZEROTHCORE_AUTH_DATABASE < $sqlfile || error "Unable to import ${sqlfile} into ${AZEROTHCORE_AUTH_DATABASE}." 55 | done 56 | else 57 | warning "auth tables already created" 58 | fi 59 | fi 60 | 61 | if [ "$DB_MANAGE_CHARACTERS" == true ]; 62 | then 63 | if [ ! -f "${DATABASE_LOCK_DIR}/database.${AZEROTHCORE_CHARACTERS_DATABASE}.lock" ]; 64 | then 65 | info "creating the character tables" 66 | touch "${DATABASE_LOCK_DIR}/database.${AZEROTHCORE_CHARACTERS_DATABASE}.lock" || error "Failed to create database lock file." 67 | cd "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SOURCE_DIR}/data/sql/base/db_characters/" || error "Failed to change AzerothCore SQL directory." 68 | for sqlfile in $(ls *.sql); 69 | do 70 | sudo mysql $AZEROTHCORE_CHARACTERS_DATABASE < $sqlfile || error "Unable to import ${sqlfile} into ${AZEROTHCORE_CHARACTERS_DATABASE}." 71 | done 72 | else 73 | warning "character tables already created" 74 | fi 75 | fi 76 | 77 | if [ "$DB_MANAGE_WORLD" == true ]; 78 | then 79 | if [ ! -f "${DATABASE_LOCK_DIR}/database.${AZEROTHCORE_WORLD_DATABASE}.lock" ]; 80 | then 81 | info "creating the world tables" 82 | touch "${DATABASE_LOCK_DIR}/database.${AZEROTHCORE_WORLD_DATABASE}.lock" || error "Failed to create database lock file." 83 | cd "${HOME}/${AZEROTHCORE_INSTALL_PARENT_DIR}/${AZEROTHCORE_SOURCE_DIR}/data/sql/base/db_world/" || error "Failed to change AzerothCore SQL directory." 84 | for sqlfile in $(ls *.sql); 85 | do 86 | sudo mysql $AZEROTHCORE_WORLD_DATABASE < $sqlfile || error "Unable to import ${sqlfile} into ${AZEROTHCORE_WORLD_DATABASE}." 87 | done 88 | else 89 | warning "character tables already created, skipping" 90 | fi 91 | fi 92 | 93 | # Prevent the need to type the password all the time 94 | cat < $HOME/.my.cnf 95 | [client] 96 | password=acore 97 | EOF 98 | 99 | if [ ! -f "${DATABASE_LOCK_DIR}/database.realmupdate.lock" ]; 100 | then 101 | touch "${DATABASE_LOCK_DIR}/database.realmupdate.lock" || error "Unable to create database lock file." 102 | 103 | info "Update the default realm to match our details..." 104 | mysql \ 105 | -u acore $AZEROTHCORE_AUTH_DATABASE \ 106 | -e "UPDATE realmlist SET name = \"${AZEROTHCORE_SERVER_REALM_NAME}\" WHERE id = 1;" \ 107 | || error "failed to update realmlist and set name" 108 | 109 | mysql \ 110 | -u acore $AZEROTHCORE_AUTH_DATABASE \ 111 | -e "UPDATE realmlist SET address = '${AZEROTHCORE_SERVER_REMOTE_ENDPOINT}' WHERE id = 1;" \ 112 | || error "failed to update realmlist and set address" 113 | 114 | mysql \ 115 | -u acore $AZEROTHCORE_AUTH_DATABASE \ 116 | -e "UPDATE realmlist SET localAddress = '${AZEROTHCORE_SERVER_BIND_IP}' WHERE id = 1;" \ 117 | || error "failed to update realmlist and set localAddress" 118 | 119 | mysql \ 120 | -u acore $AZEROTHCORE_AUTH_DATABASE \ 121 | -e "UPDATE realmlist SET localSubnetMask = '${AZEROTHCORE_SERVER_LOCAL_SUBNETMASK}' WHERE id = 1;" \ 122 | || error "failed to update realmlist and set localSubnetMask" 123 | 124 | mysql \ 125 | -u acore $AZEROTHCORE_AUTH_DATABASE \ 126 | -e "UPDATE realmlist SET port = '${AZEROTHCORE_SERVER_BIND_PORT}' WHERE id = 1;" \ 127 | || error "failed to update realmlist and set port" 128 | else 129 | warning "realm update has already happened" 130 | fi 131 | 132 | cd $WHERE_WAS_I -------------------------------------------------------------------------------- /docs/creating-quests.md: -------------------------------------------------------------------------------- 1 | # Creating Quests 2 | 3 | This is how various quests can be created via SQL. 4 | 5 | ## Dailies 6 | 7 | ```sql 8 | -- All the SET statements are used to configure the quests 9 | -- Daily Quest #1: fetch items 10 | SET 11 | @QuestLevel := 5, 12 | @QuestLevelMin := 3, 13 | @RewardMoney := 500, 14 | @Flags = 4096, 15 | @QuestTitle := 'I need me ale!', 16 | @QuestDescription := "Ah, lad, ye've come at th' right time! Listen close, for I've got a quest o' utmost importance. Y'see, I'm workin' on me maps an' calculations, but a dwarf cannae think straight without proper sustenance. That's where ye come in. Head to th' local tavern an' fetch me a keg o' their finest ale, an' ye'll have to hunt for some boar ribs, will ye? There'll be silver in it for ye, an' ye'll earn th' eternal gratitude of a dwarven scholar. So, what say ye, are ye up fer th' task?", 17 | @QuestDetails := "Bring the Cartographer some 10 Cheap Beers and 10 Crag Boar Ribs.", 18 | @QuestComplete := "Ah, ye've done it, lad! Yer success warms me dwarven heart! Th' ale's flowin' an' th' ribs are cookin', thanks t' ye. Take this silver, ye've more than earned it!", 19 | @DailyItem1 := 19222, 20 | @DailyItem1Count := 10, 21 | @DailyItem2 := 2886, 22 | @DailyItem2Count := 10, 23 | @QuestObjective1Text := "Fetch 10 Cheap Beers", 24 | @QuestObjective2Text := "Hunt 10 Crag Boar Ribs"; 25 | 26 | -- First delete the quest if it already exists. 27 | DELETE FROM `quest_template` WHERE (`ID` = @Entry+1); 28 | INSERT INTO `quest_template` (`ID`, `QuestType`, `QuestLevel`, `MinLevel`, `QuestSortID`, `QuestInfoID`, `SuggestedGroupNum`, `RequiredFactionId1`, `RequiredFactionId2`, `RequiredFactionValue1`, `RequiredFactionValue2`, `RewardNextQuest`, `RewardXPDifficulty`, `RewardMoney`, `RewardMoneyDifficulty`, `RewardBonusMoney`, `RewardDisplaySpell`, `RewardSpell`, `RewardHonor`, `RewardKillHonor`, `StartItem`, `Flags`, `RequiredPlayerKills`, `RewardItem1`, `RewardAmount1`, `RewardItem2`, `RewardAmount2`, `RewardItem3`, `RewardAmount3`, `RewardItem4`, `RewardAmount4`, `ItemDrop1`, `ItemDropQuantity1`, `ItemDrop2`, `ItemDropQuantity2`, `ItemDrop3`, `ItemDropQuantity3`, `ItemDrop4`, `ItemDropQuantity4`, `RewardChoiceItemID1`, `RewardChoiceItemQuantity1`, `RewardChoiceItemID2`, `RewardChoiceItemQuantity2`, `RewardChoiceItemID3`, `RewardChoiceItemQuantity3`, `RewardChoiceItemID4`, `RewardChoiceItemQuantity4`, `RewardChoiceItemID5`, `RewardChoiceItemQuantity5`, `RewardChoiceItemID6`, `RewardChoiceItemQuantity6`, `POIContinent`, `POIx`, `POIy`, `POIPriority`, `RewardTitle`, `RewardTalents`, `RewardArenaPoints`, `RewardFactionID1`, `RewardFactionValue1`, `RewardFactionOverride1`, `RewardFactionID2`, `RewardFactionValue2`, `RewardFactionOverride2`, `RewardFactionID3`, `RewardFactionValue3`, `RewardFactionOverride3`, `RewardFactionID4`, `RewardFactionValue4`, `RewardFactionOverride4`, `RewardFactionID5`, `RewardFactionValue5`, `RewardFactionOverride5`, `TimeAllowed`, `AllowableRaces`, `LogTitle`, `LogDescription`, `QuestDescription`, `AreaDescription`, `QuestCompletionLog`, `RequiredNpcOrGo1`, `RequiredNpcOrGo2`, `RequiredNpcOrGo3`, `RequiredNpcOrGo4`, `RequiredNpcOrGoCount1`, `RequiredNpcOrGoCount2`, `RequiredNpcOrGoCount3`, `RequiredNpcOrGoCount4`, `RequiredItemId1`, `RequiredItemId2`, `RequiredItemId3`, `RequiredItemId4`, `RequiredItemId5`, `RequiredItemId6`, `RequiredItemCount1`, `RequiredItemCount2`, `RequiredItemCount3`, `RequiredItemCount4`, `RequiredItemCount5`, `RequiredItemCount6`, `Unknown0`, `ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES (@Entry+1, 2, @QuestLevel, @QuestLevelMin, 0, 0, 0, 0, 0, 0, 0, 0, 0, @RewardMoney, 0, 0, 0, 0, 0, 0, 0, @Flags, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @QuestTitle, @QuestDetails, @QuestDescription, '', @QuestComplete, 0, 0, 0, 0, 0, 0, 0, 0, @DailyItem1, @DailyItem2, 0, 0, 0, 0, @DailyItem1Count, @DailyItem2Count, 0, 0, 0, 0, 0, @QuestObjective1Text, @QuestObjective2Text, '', '', 0); 29 | DELETE FROM `quest_request_items` WHERE (`ID` = @Entry+1); 30 | INSERT INTO `quest_request_items` (`ID`, `EmoteOnComplete`, `EmoteOnIncomplete`, `CompletionText`, `VerifiedBuild`) VALUES (@Entry+1, 4, 0, @QuestComplete, 0); 31 | DELETE FROM `quest_offer_reward` WHERE (`ID` = @Entry+1); 32 | INSERT INTO `quest_offer_reward` (`ID`, `Emote1`, `Emote2`, `Emote3`, `Emote4`, `EmoteDelay1`, `EmoteDelay2`, `EmoteDelay3`, `EmoteDelay4`, `RewardText`, `VerifiedBuild`) VALUES (@Entry+1, 4, 0, 0, 0, 0, 0, 0, 0, @QuestComplete, 0); 33 | DELETE FROM `creature_queststarter` WHERE (`quest` = @Entry+1) AND (`id` IN (@Entry+1)); 34 | INSERT INTO `creature_queststarter` (`id`, `quest`) VALUES (@Entry+1, @Entry+1); 35 | DELETE FROM `creature_questender` WHERE (`quest` = @Entry+1) AND (`id` IN (@Entry+1)); 36 | INSERT INTO `creature_questender` (`id`, `quest`) VALUES (@Entry+1, @Entry+1); 37 | ``` 38 | 39 | -- Daily Quest #2: kill beasts 40 | SET @QuestLevel := 5, @QuestLevelMin := 3, @RewardMoney := 500, @Flags = 4096; 41 | SET @QuestTitle := 'Silence the Roars for Restful Slumbers'; 42 | SET @QuestDescription := "Ah, there ye are! Now, listen up, lad. Between th' black bears an' th' snow leopards makin' a racket, a dwarf can't catch a wink o' sleep. They prowl too close to me abode, an' it's high time someone did somethin' 'bout it. I need ye t' go out there an' put down, let's say, ten o' each. It's a tough ask, I know, but there'll be silver waitin' fer ye. Will ye give a dwarf some peace?"; 43 | SET @QuestDetails := "Eliminate 10 Snow Tracker Wolf and 10 Juvenile Snow Leopards that are disturbing a dwarf's sleep."; 44 | SET @QuestComplete := "Ye've done it! Finally, silence reigns, an' I can rest me eyes. Here's yer well-earned silver, lad. Ye've got me eternal gratitude."; 45 | SET @QuestObjective1Text := "Kill Juvenile Snow Leopards"; 46 | SET @QuestObjective2Text := "Kill Snow Tracker Wolves"; 47 | SET @DailyGameObject1 := 1199; -- Juvenile Snow Leopard 48 | SET @DailyGameObject1Count := 10; 49 | SET @DailyGameObject2 := 1138; -- Snow Tracker Wolf 50 | SET @DailyGameObject2Count := 10; 51 | DELETE FROM `quest_template` WHERE (`ID` = @Entry+2); 52 | INSERT INTO `quest_template` (`ID`, `QuestType`, `QuestLevel`, `MinLevel`, `QuestSortID`, `QuestInfoID`, `SuggestedGroupNum`, `RequiredFactionId1`, `RequiredFactionId2`, `RequiredFactionValue1`, `RequiredFactionValue2`, `RewardNextQuest`, `RewardXPDifficulty`, `RewardMoney`, `RewardMoneyDifficulty`, `RewardBonusMoney`, `RewardDisplaySpell`, `RewardSpell`, `RewardHonor`, `RewardKillHonor`, `StartItem`, `Flags`, `RequiredPlayerKills`, `RewardItem1`, `RewardAmount1`, `RewardItem2`, `RewardAmount2`, `RewardItem3`, `RewardAmount3`, `RewardItem4`, `RewardAmount4`, `ItemDrop1`, `ItemDropQuantity1`, `ItemDrop2`, `ItemDropQuantity2`, `ItemDrop3`, `ItemDropQuantity3`, `ItemDrop4`, `ItemDropQuantity4`, `RewardChoiceItemID1`, `RewardChoiceItemQuantity1`, `RewardChoiceItemID2`, `RewardChoiceItemQuantity2`, `RewardChoiceItemID3`, `RewardChoiceItemQuantity3`, `RewardChoiceItemID4`, `RewardChoiceItemQuantity4`, `RewardChoiceItemID5`, `RewardChoiceItemQuantity5`, `RewardChoiceItemID6`, `RewardChoiceItemQuantity6`, `POIContinent`, `POIx`, `POIy`, `POIPriority`, `RewardTitle`, `RewardTalents`, `RewardArenaPoints`, `RewardFactionID1`, `RewardFactionValue1`, `RewardFactionOverride1`, `RewardFactionID2`, `RewardFactionValue2`, `RewardFactionOverride2`, `RewardFactionID3`, `RewardFactionValue3`, `RewardFactionOverride3`, `RewardFactionID4`, `RewardFactionValue4`, `RewardFactionOverride4`, `RewardFactionID5`, `RewardFactionValue5`, `RewardFactionOverride5`, `TimeAllowed`, `AllowableRaces`, `LogTitle`, `LogDescription`, `QuestDescription`, `AreaDescription`, `QuestCompletionLog`, `RequiredNpcOrGo1`, `RequiredNpcOrGo2`, `RequiredNpcOrGo3`, `RequiredNpcOrGo4`, `RequiredNpcOrGoCount1`, `RequiredNpcOrGoCount2`, `RequiredNpcOrGoCount3`, `RequiredNpcOrGoCount4`, `RequiredItemId1`, `RequiredItemId2`, `RequiredItemId3`, `RequiredItemId4`, `RequiredItemId5`, `RequiredItemId6`, `RequiredItemCount1`, `RequiredItemCount2`, `RequiredItemCount3`, `RequiredItemCount4`, `RequiredItemCount5`, `RequiredItemCount6`, `Unknown0`, `ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES (@Entry+2, 2, @QuestLevel, @QuestLevelMin, 0, 0, 0, 0, 0, 0, 0, 0, 0, @RewardMoney, 0, 0, 0, 0, 0, 0, 0, @Flags, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @QuestTitle, @QuestDetails, @QuestDescription, '', @QuestComplete, @DailyGameObject1, @DailyGameObject2, 0, 0, @DailyGameObject1Count, @DailyGameObject2Count, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @QuestObjective1Text, @QuestObjective2Text, '', '', 0); 53 | DELETE FROM `quest_offer_reward` WHERE (`ID` = @Entry+2); 54 | INSERT INTO `quest_offer_reward` (`ID`, `Emote1`, `Emote2`, `Emote3`, `Emote4`, `EmoteDelay1`, `EmoteDelay2`, `EmoteDelay3`, `EmoteDelay4`, `RewardText`, `VerifiedBuild`) VALUES (@Entry+2, 2, 0, 0, 0, 0, 0, 0, 0, @QuestComplete, 0); 55 | DELETE FROM `quest_request_items` WHERE (`ID` = @Entry+2); 56 | INSERT INTO `quest_request_items` (`ID`, `EmoteOnComplete`, `EmoteOnIncomplete`, `CompletionText`, `VerifiedBuild`) VALUES (@Entry+2, 2, 0, @QuestComplete, 0); 57 | DELETE FROM `creature_queststarter` WHERE (`quest` = @Entry+2) AND (`id` IN (@Entry+1)); 58 | INSERT INTO `creature_queststarter` (`id`, `quest`) VALUES (@Entry+1, @Entry+2); 59 | DELETE FROM `creature_questender` WHERE (`quest` = @Entry+2) AND (`id` IN (@Entry+1)); 60 | INSERT INTO `creature_questender` (`id`, `quest`) VALUES (@Entry+1, @Entry+2); -------------------------------------------------------------------------------- /sql/world/a-02-starting-mount-accessiblity.sql: -------------------------------------------------------------------------------- 1 | -- 02 setup human readable names for key IDs in the DB 2 | -- These are all values for various things throughout the game. 3 | 4 | -- 02.1 5 | -- These are all the basics race mounts. The cheap, 60% ones. 6 | SET 7 | @mountAllianceHumanBasic := 2411, 8 | @mountAllianceDwarfBasic := 5864, 9 | @mountAllianceNightElfBasic := 8629, 10 | @mountAllianceGnomeBasic := 13322, 11 | @mountAllianceDraineiBasic := 28481, 12 | @mountHordeOrcBasic := 5665, 13 | @mountHordeUndeadBasic := 13331, 14 | @mountHordeTaurenBasic := 15277, 15 | @mountHordeTrollBasic := 8588, 16 | @mountHordeBloodElfBasic := 29221; 17 | 18 | -- 02.2 19 | -- These are the riding trainers in each starting zone 20 | SET 21 | @ridingTrainerHumanRandalHunter := 4732, 22 | @ridingTrainerOrcKildar := 4752; 23 | 24 | -- 02.3 25 | -- These are the quest IDs for each faction's riding trainer 26 | SET 27 | @ridingTrainerHumanRandalHunterQuest := 91100000, 28 | @ridingTrainerOrcKildarQuest := 91100001; 29 | 30 | -- 03 mount updates for level 10 quest giver/rewarder 31 | 32 | -- 03.1 make the mounts usable at level 10 33 | -- Update these basic mounts to be usable at level 1 34 | -- Riding skill 75 will be taught to the player, so leaving 35 | -- that alone here. 36 | UPDATE acore_world.item_template SET RequiredLevel=10 WHERE entry=@mountAllianceHumanBasic; 37 | UPDATE acore_world.item_template SET RequiredLevel=10 WHERE entry=@mountAllianceDwarfBasic; 38 | UPDATE acore_world.item_template SET RequiredLevel=10 WHERE entry=@mountAllianceNightElfBasic; 39 | UPDATE acore_world.item_template SET RequiredLevel=10 WHERE entry=@mountAllianceGnomeBasic; 40 | UPDATE acore_world.item_template SET RequiredLevel=10 WHERE entry=@mountAllianceDraineiBasic; 41 | UPDATE acore_world.item_template SET RequiredLevel=10 WHERE entry=@mountHordeOrcBasic; 42 | UPDATE acore_world.item_template SET RequiredLevel=10 WHERE entry=@mountHordeUndeadBasic; 43 | UPDATE acore_world.item_template SET RequiredLevel=10 WHERE entry=@mountHordeTaurenBasic; 44 | UPDATE acore_world.item_template SET RequiredLevel=10 WHERE entry=@mountHordeTrollBasic; 45 | UPDATE acore_world.item_template SET RequiredLevel=10 WHERE entry=@mountHordeBloodElfBasic; 46 | 47 | 48 | -- 03.2 update the "spell" to allow it to be bought for 1s at level 10 49 | UPDATE npc_trainer SET MoneyCost=100, ReqLevel=10 WHERE ID=202010 AND SpellID=33388; 50 | 51 | -- 03.3 add the quest 52 | -- Notes: 53 | -- * this quest auto-completes. You don't have to do anything when accepting it, it just accepts and then completes, giving you the reward 54 | -- * this means you have to use quest_offer_reward for the gossip text shown because that's the final gossip shown to the player, because the quest basically auto-completes and 55 | -- jumps to the reward page. 56 | 57 | -- 03.3.1 Human riding trainer quest 58 | DELETE FROM `quest_template` WHERE (`ID` = @ridingTrainerHumanRandalHunterQuest); 59 | INSERT INTO `quest_template` (`ID`, `QuestType`, `QuestLevel`, `MinLevel`, `QuestSortID`, `QuestInfoID`, `SuggestedGroupNum`, `RequiredFactionId1`, `RequiredFactionId2`, `RequiredFactionValue1`, `RequiredFactionValue2`, `RewardNextQuest`, `RewardXPDifficulty`, `RewardMoney`, `RewardMoneyDifficulty`, `RewardBonusMoney`, `RewardDisplaySpell`, `RewardSpell`, `RewardHonor`, `RewardKillHonor`, `StartItem`, `Flags`, `RequiredPlayerKills`, `RewardItem1`, `RewardAmount1`, `RewardItem2`, `RewardAmount2`, `RewardItem3`, `RewardAmount3`, `RewardItem4`, `RewardAmount4`, `ItemDrop1`, `ItemDropQuantity1`, `ItemDrop2`, `ItemDropQuantity2`, `ItemDrop3`, `ItemDropQuantity3`, `ItemDrop4`, `ItemDropQuantity4`, `RewardChoiceItemID1`, `RewardChoiceItemQuantity1`, `RewardChoiceItemID2`, `RewardChoiceItemQuantity2`, `RewardChoiceItemID3`, `RewardChoiceItemQuantity3`, `RewardChoiceItemID4`, `RewardChoiceItemQuantity4`, `RewardChoiceItemID5`, `RewardChoiceItemQuantity5`, `RewardChoiceItemID6`, `RewardChoiceItemQuantity6`, `POIContinent`, `POIx`, `POIy`, `POIPriority`, `RewardTitle`, `RewardTalents`, `RewardArenaPoints`, `RewardFactionID1`, `RewardFactionValue1`, `RewardFactionOverride1`, `RewardFactionID2`, `RewardFactionValue2`, `RewardFactionOverride2`, `RewardFactionID3`, `RewardFactionValue3`, `RewardFactionOverride3`, `RewardFactionID4`, `RewardFactionValue4`, `RewardFactionOverride4`, `RewardFactionID5`, `RewardFactionValue5`, `RewardFactionOverride5`, `TimeAllowed`, `AllowableRaces`, `LogTitle`, `LogDescription`, `QuestDescription`, `AreaDescription`, `QuestCompletionLog`, `RequiredNpcOrGo1`, `RequiredNpcOrGo2`, `RequiredNpcOrGo3`, `RequiredNpcOrGo4`, `RequiredNpcOrGoCount1`, `RequiredNpcOrGoCount2`, `RequiredNpcOrGoCount3`, `RequiredNpcOrGoCount4`, `RequiredItemId1`, `RequiredItemId2`, `RequiredItemId3`, `RequiredItemId4`, `RequiredItemId5`, `RequiredItemId6`, `RequiredItemCount1`, `RequiredItemCount2`, `RequiredItemCount3`, `RequiredItemCount4`, `RequiredItemCount5`, `RequiredItemCount6`, `Unknown0`, `ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES 60 | (@ridingTrainerHumanRandalHunterQuest, 0, 10, 10, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @mountAllianceHumanBasic, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 'No Time to Waste', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', '', '', 0); 61 | 62 | DELETE FROM `quest_offer_reward` WHERE (`ID` = @ridingTrainerHumanRandalHunterQuest); 63 | INSERT INTO `quest_offer_reward` (`ID`, `Emote1`, `Emote2`, `Emote3`, `Emote4`, `EmoteDelay1`, `EmoteDelay2`, `EmoteDelay3`, `EmoteDelay4`, `RewardText`, `VerifiedBuild`) VALUES 64 | (@ridingTrainerHumanRandalHunterQuest, 1, 0, 0, 0, 0, 0, 0, 0, "Looks like you're some sort of great hero that the King has high hopes for. They've ordered me to gift you this mount. I hope this helps, but don't expect riding lessons for free. I have to charge something, great hero or no.", 0); 65 | 66 | -- 03.3.2 Orc riding trainer quest 67 | DELETE FROM `quest_template` WHERE (`ID` = @ridingTrainerOrcKildarQuest); 68 | INSERT INTO `quest_template` (`ID`, `QuestType`, `QuestLevel`, `MinLevel`, `QuestSortID`, `QuestInfoID`, `SuggestedGroupNum`, `RequiredFactionId1`, `RequiredFactionId2`, `RequiredFactionValue1`, `RequiredFactionValue2`, `RewardNextQuest`, `RewardXPDifficulty`, `RewardMoney`, `RewardMoneyDifficulty`, `RewardBonusMoney`, `RewardDisplaySpell`, `RewardSpell`, `RewardHonor`, `RewardKillHonor`, `StartItem`, `Flags`, `RequiredPlayerKills`, `RewardItem1`, `RewardAmount1`, `RewardItem2`, `RewardAmount2`, `RewardItem3`, `RewardAmount3`, `RewardItem4`, `RewardAmount4`, `ItemDrop1`, `ItemDropQuantity1`, `ItemDrop2`, `ItemDropQuantity2`, `ItemDrop3`, `ItemDropQuantity3`, `ItemDrop4`, `ItemDropQuantity4`, `RewardChoiceItemID1`, `RewardChoiceItemQuantity1`, `RewardChoiceItemID2`, `RewardChoiceItemQuantity2`, `RewardChoiceItemID3`, `RewardChoiceItemQuantity3`, `RewardChoiceItemID4`, `RewardChoiceItemQuantity4`, `RewardChoiceItemID5`, `RewardChoiceItemQuantity5`, `RewardChoiceItemID6`, `RewardChoiceItemQuantity6`, `POIContinent`, `POIx`, `POIy`, `POIPriority`, `RewardTitle`, `RewardTalents`, `RewardArenaPoints`, `RewardFactionID1`, `RewardFactionValue1`, `RewardFactionOverride1`, `RewardFactionID2`, `RewardFactionValue2`, `RewardFactionOverride2`, `RewardFactionID3`, `RewardFactionValue3`, `RewardFactionOverride3`, `RewardFactionID4`, `RewardFactionValue4`, `RewardFactionOverride4`, `RewardFactionID5`, `RewardFactionValue5`, `RewardFactionOverride5`, `TimeAllowed`, `AllowableRaces`, `LogTitle`, `LogDescription`, `QuestDescription`, `AreaDescription`, `QuestCompletionLog`, `RequiredNpcOrGo1`, `RequiredNpcOrGo2`, `RequiredNpcOrGo3`, `RequiredNpcOrGo4`, `RequiredNpcOrGoCount1`, `RequiredNpcOrGoCount2`, `RequiredNpcOrGoCount3`, `RequiredNpcOrGoCount4`, `RequiredItemId1`, `RequiredItemId2`, `RequiredItemId3`, `RequiredItemId4`, `RequiredItemId5`, `RequiredItemId6`, `RequiredItemCount1`, `RequiredItemCount2`, `RequiredItemCount3`, `RequiredItemCount4`, `RequiredItemCount5`, `RequiredItemCount6`, `Unknown0`, `ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES 69 | (@ridingTrainerOrcKildarQuest, 0, 10, 10, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5665, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 'No Time to Waste', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '', '', '', 0); 70 | 71 | DELETE FROM `quest_offer_reward` WHERE (`ID` = @ridingTrainerOrcKildarQuest); 72 | INSERT INTO `quest_offer_reward` (`ID`, `Emote1`, `Emote2`, `Emote3`, `Emote4`, `EmoteDelay1`, `EmoteDelay2`, `EmoteDelay3`, `EmoteDelay4`, `RewardText`, `VerifiedBuild`) VALUES 73 | (@ridingTrainerOrcKildarQuest, 1, 0, 0, 0, 0, 0, 0, 0, "Looks like you're some sort of great hero that the Warchief has high hopes for. They've ordered me to gift you this mount. I hope this helps, but don't expect riding lessons for free. I have to charge something, great hero or no.", 0); 74 | 75 | -- 03.4 add the quest to the "starter area" riding trainers 76 | -- 03.4.1 Human 77 | DELETE FROM `creature_queststarter` WHERE (`quest` = @ridingTrainerHumanRandalHunterQuest) AND (`id` IN (@ridingTrainerHumanRandalHunter)); 78 | INSERT INTO `creature_queststarter` (`id`, `quest`) VALUES (@ridingTrainerHumanRandalHunter, @ridingTrainerHumanRandalHunterQuest); 79 | DELETE FROM `creature_questender` WHERE (`quest` = @ridingTrainerHumanRandalHunterQuest) AND (`id` IN (@ridingTrainerHumanRandalHunter)); 80 | INSERT INTO `creature_questender` (`id`, `quest`) VALUES(@ridingTrainerHumanRandalHunter, @ridingTrainerHumanRandalHunterQuest); 81 | 82 | -- 03.4.2 Orc 83 | DELETE FROM `creature_queststarter` WHERE (`quest` = @ridingTrainerOrcKildarQuest) AND (`id` IN (@ridingTrainerOrcKildar)); 84 | INSERT INTO `creature_queststarter` (`id`, `quest`) VALUES (@ridingTrainerOrcKildar, @ridingTrainerOrcKildarQuest); 85 | DELETE FROM `creature_questender` WHERE (`quest` = @ridingTrainerOrcKildarQuest) AND (`id` IN (@ridingTrainerOrcKildar)); 86 | INSERT INTO `creature_questender` (`id`, `quest`) VALUES(@ridingTrainerOrcKildar, @ridingTrainerOrcKildarQuest); 87 | -------------------------------------------------------------------------------- /docs/03-the-cartographers.example.sql: -------------------------------------------------------------------------------- 1 | -- 03 The Cartographers 2 | -- A guild officially funded by the King of Stormwind 3 | -- and the Warchief. The only joint venture between the two 4 | -- warring nations. 5 | 6 | -- Placement information and IDs 7 | SET 8 | @Entry := 9200000, 9 | @EntrySet := 5, 10 | @MAP_EASTERN_KINGDOMS := 0, 11 | @MAP_KALIMDOR := 1, 12 | @MAP_OUTLAND := 530, 13 | @MAP_NORTHREND := 571; 14 | 15 | -- NPCs: 16 | 17 | -- ########################### 18 | -- Craig Flintcrag; Dun Morogh 19 | -- ########################### 20 | SET @X := -5566.1391, @Y := -537.76470, @Z := 410.716522, @O := 5.922254; 21 | SET @Model := 3306, @Name := "Craig Flintcrag", @Subname := "The Cartographers", @Icon := "Speak", @GossipMenu := 0, @MinLevel := 80, @MaxLevel := 80, @Faction := 12, @NPCFlag := 4098, @Scale := 1.0, @Rank := 0, @Type := 7, @TypeFlags := 0, @FlagsExtra := 16777218; 22 | 23 | -- Creature 24 | DELETE FROM `creature` WHERE `id1`=@Entry+1; 25 | DELETE FROM `creature_template` WHERE `entry`=@Entry+1; 26 | INSERT INTO `creature_template` (`entry`, `modelid1`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `scale`, `rank`, `unit_class`, `unit_flags`, `type`, `type_flags`, `RegenHealth`, `flags_extra`) VALUES (@Entry+1, @Model, @Name, @Subname, @Icon, @GossipMenu, @MinLevel, @MaxLevel, @Faction, @NPCFlag, 1, 1, @Scale, @Rank, 1, 2, @Type, @TypeFlags, 1, @FlagsExtra); 27 | INSERT INTO `creature` (`id1`,`map`,`position_x`,`position_y`,`position_z`,`orientation`) VALUES (@Entry+1,@MAP_EASTERN_KINGDOMS,@X,@Y,@Z,@O); 28 | 29 | -- Daily Quest #1: fetch items 30 | SET @QuestLevel := 5, @QuestLevelMin := 3, @RewardMoney := 500, @Flags = 4096; 31 | SET @QuestTitle := 'I need me ale!'; 32 | SET @QuestDescription := "Ah, lad, ye've come at th' right time! Listen close, for I've got a quest o' utmost importance. Y'see, I'm workin' on me maps an' calculations, but a dwarf cannae think straight without proper sustenance. That's where ye come in. Head to th' local tavern an' fetch me a keg o' their finest ale, an' ye'll have to hunt for some boar ribs, will ye? There'll be silver in it for ye, an' ye'll earn th' eternal gratitude of a dwarven scholar. So, what say ye, are ye up fer th' task?"; 33 | SET @QuestDetails := "Bring the Cartographer some 10 Cheap Beers and 10 Crag Boar Ribs."; 34 | SET @QuestComplete := "Ah, ye've done it, lad! Yer success warms me dwarven heart! Th' ale's flowin' an' th' ribs are cookin', thanks t' ye. Take this silver; ye've more than earned it!"; 35 | SET @DailyItem1 := 19222; 36 | SET @DailyItem1Count := 10; 37 | SET @DailyItem2 := 2886; 38 | SET @DailyItem2Count := 10; 39 | SET @QuestObjective1Text := "Fetch 10 Cheap Beers"; 40 | SET @QuestObjective2Text := "Hunt 10 Crag Boar Ribs"; 41 | DELETE FROM `quest_template` WHERE (`ID` = @Entry+1); 42 | INSERT INTO `quest_template` (`ID`, `QuestType`, `QuestLevel`, `MinLevel`, `QuestSortID`, `QuestInfoID`, `SuggestedGroupNum`, `RequiredFactionId1`, `RequiredFactionId2`, `RequiredFactionValue1`, `RequiredFactionValue2`, `RewardNextQuest`, `RewardXPDifficulty`, `RewardMoney`, `RewardMoneyDifficulty`, `RewardBonusMoney`, `RewardDisplaySpell`, `RewardSpell`, `RewardHonor`, `RewardKillHonor`, `StartItem`, `Flags`, `RequiredPlayerKills`, `RewardItem1`, `RewardAmount1`, `RewardItem2`, `RewardAmount2`, `RewardItem3`, `RewardAmount3`, `RewardItem4`, `RewardAmount4`, `ItemDrop1`, `ItemDropQuantity1`, `ItemDrop2`, `ItemDropQuantity2`, `ItemDrop3`, `ItemDropQuantity3`, `ItemDrop4`, `ItemDropQuantity4`, `RewardChoiceItemID1`, `RewardChoiceItemQuantity1`, `RewardChoiceItemID2`, `RewardChoiceItemQuantity2`, `RewardChoiceItemID3`, `RewardChoiceItemQuantity3`, `RewardChoiceItemID4`, `RewardChoiceItemQuantity4`, `RewardChoiceItemID5`, `RewardChoiceItemQuantity5`, `RewardChoiceItemID6`, `RewardChoiceItemQuantity6`, `POIContinent`, `POIx`, `POIy`, `POIPriority`, `RewardTitle`, `RewardTalents`, `RewardArenaPoints`, `RewardFactionID1`, `RewardFactionValue1`, `RewardFactionOverride1`, `RewardFactionID2`, `RewardFactionValue2`, `RewardFactionOverride2`, `RewardFactionID3`, `RewardFactionValue3`, `RewardFactionOverride3`, `RewardFactionID4`, `RewardFactionValue4`, `RewardFactionOverride4`, `RewardFactionID5`, `RewardFactionValue5`, `RewardFactionOverride5`, `TimeAllowed`, `AllowableRaces`, `LogTitle`, `LogDescription`, `QuestDescription`, `AreaDescription`, `QuestCompletionLog`, `RequiredNpcOrGo1`, `RequiredNpcOrGo2`, `RequiredNpcOrGo3`, `RequiredNpcOrGo4`, `RequiredNpcOrGoCount1`, `RequiredNpcOrGoCount2`, `RequiredNpcOrGoCount3`, `RequiredNpcOrGoCount4`, `RequiredItemId1`, `RequiredItemId2`, `RequiredItemId3`, `RequiredItemId4`, `RequiredItemId5`, `RequiredItemId6`, `RequiredItemCount1`, `RequiredItemCount2`, `RequiredItemCount3`, `RequiredItemCount4`, `RequiredItemCount5`, `RequiredItemCount6`, `Unknown0`, `ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES (@Entry+1, 2, @QuestLevel, @QuestLevelMin, 0, 0, 0, 0, 0, 0, 0, 0, 0, @RewardMoney, 0, 0, 0, 0, 0, 0, 0, @Flags, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @QuestTitle, @QuestDetails, @QuestDescription, '', @QuestComplete, 0, 0, 0, 0, 0, 0, 0, 0, @DailyItem1, @DailyItem2, 0, 0, 0, 0, @DailyItem1Count, @DailyItem2Count, 0, 0, 0, 0, 0, @QuestObjective1Text, @QuestObjective2Text, '', '', 0); 43 | DELETE FROM `quest_request_items` WHERE (`ID` = @Entry+1); 44 | INSERT INTO `quest_request_items` (`ID`, `EmoteOnComplete`, `EmoteOnIncomplete`, `CompletionText`, `VerifiedBuild`) VALUES (@Entry+1, 4, 0, @QuestComplete, 0); 45 | DELETE FROM `quest_offer_reward` WHERE (`ID` = @Entry+1); 46 | INSERT INTO `quest_offer_reward` (`ID`, `Emote1`, `Emote2`, `Emote3`, `Emote4`, `EmoteDelay1`, `EmoteDelay2`, `EmoteDelay3`, `EmoteDelay4`, `RewardText`, `VerifiedBuild`) VALUES (@Entry+1, 4, 0, 0, 0, 0, 0, 0, 0, @QuestComplete, 0); 47 | DELETE FROM `creature_queststarter` WHERE (`quest` = @Entry+1) AND (`id` IN (@Entry+1)); 48 | INSERT INTO `creature_queststarter` (`id`, `quest`) VALUES (@Entry+1, @Entry+1); 49 | DELETE FROM `creature_questender` WHERE (`quest` = @Entry+1) AND (`id` IN (@Entry+1)); 50 | INSERT INTO `creature_questender` (`id`, `quest`) VALUES (@Entry+1, @Entry+1); 51 | 52 | -- Daily Quest #2: kill beasts 53 | SET @QuestLevel := 5, @QuestLevelMin := 3, @RewardMoney := 500, @Flags = 4096; 54 | SET @QuestTitle := 'Silence the Roars for Restful Slumbers'; 55 | SET @QuestDescription := "Ah, there ye are! Now, listen up, lad. Between th' black bears an' th' snow leopards makin' a racket, a dwarf can't catch a wink o' sleep. They prowl too close to me abode, an' it's high time someone did somethin' 'bout it. I need ye t' go out there an' put down, let's say, ten o' each. It's a tough ask, I know, but there'll be silver waitin' fer ye. Will ye give a dwarf some peace?"; 56 | SET @QuestDetails := "Eliminate 10 Snow Tracker Wolf and 10 Juvenile Snow Leopards that are disturbing a dwarf's sleep."; 57 | SET @QuestComplete := "Ye've done it! Finally, silence reigns, an' I can rest me eyes. Here's yer well-earned silver, lad. Ye've got me eternal gratitude."; 58 | SET @QuestObjective1Text := "Kill Juvenile Snow Leopards"; 59 | SET @QuestObjective2Text := "Kill Snow Tracker Wolves"; 60 | SET @DailyGameObject1 := 1199; -- Juvenile Snow Leopard 61 | SET @DailyGameObject1Count := 10; 62 | SET @DailyGameObject2 := 1138; -- Snow Tracker Wolf 63 | SET @DailyGameObject2Count := 10; 64 | DELETE FROM `quest_template` WHERE (`ID` = @Entry+2); 65 | INSERT INTO `quest_template` (`ID`, `QuestType`, `QuestLevel`, `MinLevel`, `QuestSortID`, `QuestInfoID`, `SuggestedGroupNum`, `RequiredFactionId1`, `RequiredFactionId2`, `RequiredFactionValue1`, `RequiredFactionValue2`, `RewardNextQuest`, `RewardXPDifficulty`, `RewardMoney`, `RewardMoneyDifficulty`, `RewardBonusMoney`, `RewardDisplaySpell`, `RewardSpell`, `RewardHonor`, `RewardKillHonor`, `StartItem`, `Flags`, `RequiredPlayerKills`, `RewardItem1`, `RewardAmount1`, `RewardItem2`, `RewardAmount2`, `RewardItem3`, `RewardAmount3`, `RewardItem4`, `RewardAmount4`, `ItemDrop1`, `ItemDropQuantity1`, `ItemDrop2`, `ItemDropQuantity2`, `ItemDrop3`, `ItemDropQuantity3`, `ItemDrop4`, `ItemDropQuantity4`, `RewardChoiceItemID1`, `RewardChoiceItemQuantity1`, `RewardChoiceItemID2`, `RewardChoiceItemQuantity2`, `RewardChoiceItemID3`, `RewardChoiceItemQuantity3`, `RewardChoiceItemID4`, `RewardChoiceItemQuantity4`, `RewardChoiceItemID5`, `RewardChoiceItemQuantity5`, `RewardChoiceItemID6`, `RewardChoiceItemQuantity6`, `POIContinent`, `POIx`, `POIy`, `POIPriority`, `RewardTitle`, `RewardTalents`, `RewardArenaPoints`, `RewardFactionID1`, `RewardFactionValue1`, `RewardFactionOverride1`, `RewardFactionID2`, `RewardFactionValue2`, `RewardFactionOverride2`, `RewardFactionID3`, `RewardFactionValue3`, `RewardFactionOverride3`, `RewardFactionID4`, `RewardFactionValue4`, `RewardFactionOverride4`, `RewardFactionID5`, `RewardFactionValue5`, `RewardFactionOverride5`, `TimeAllowed`, `AllowableRaces`, `LogTitle`, `LogDescription`, `QuestDescription`, `AreaDescription`, `QuestCompletionLog`, `RequiredNpcOrGo1`, `RequiredNpcOrGo2`, `RequiredNpcOrGo3`, `RequiredNpcOrGo4`, `RequiredNpcOrGoCount1`, `RequiredNpcOrGoCount2`, `RequiredNpcOrGoCount3`, `RequiredNpcOrGoCount4`, `RequiredItemId1`, `RequiredItemId2`, `RequiredItemId3`, `RequiredItemId4`, `RequiredItemId5`, `RequiredItemId6`, `RequiredItemCount1`, `RequiredItemCount2`, `RequiredItemCount3`, `RequiredItemCount4`, `RequiredItemCount5`, `RequiredItemCount6`, `Unknown0`, `ObjectiveText1`, `ObjectiveText2`, `ObjectiveText3`, `ObjectiveText4`, `VerifiedBuild`) VALUES (@Entry+2, 2, @QuestLevel, @QuestLevelMin, 0, 0, 0, 0, 0, 0, 0, 0, 0, @RewardMoney, 0, 0, 0, 0, 0, 0, 0, @Flags, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @QuestTitle, @QuestDetails, @QuestDescription, '', @QuestComplete, @DailyGameObject1, @DailyGameObject2, 0, 0, @DailyGameObject1Count, @DailyGameObject2Count, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @QuestObjective1Text, @QuestObjective2Text, '', '', 0); 66 | DELETE FROM `quest_offer_reward` WHERE (`ID` = @Entry+2); 67 | INSERT INTO `quest_offer_reward` (`ID`, `Emote1`, `Emote2`, `Emote3`, `Emote4`, `EmoteDelay1`, `EmoteDelay2`, `EmoteDelay3`, `EmoteDelay4`, `RewardText`, `VerifiedBuild`) VALUES (@Entry+2, 2, 0, 0, 0, 0, 0, 0, 0, @QuestComplete, 0); 68 | DELETE FROM `quest_request_items` WHERE (`ID` = @Entry+2); 69 | INSERT INTO `quest_request_items` (`ID`, `EmoteOnComplete`, `EmoteOnIncomplete`, `CompletionText`, `VerifiedBuild`) VALUES (@Entry+2, 2, 0, @QuestComplete, 0); 70 | DELETE FROM `creature_queststarter` WHERE (`quest` = @Entry+2) AND (`id` IN (@Entry+1)); 71 | INSERT INTO `creature_queststarter` (`id`, `quest`) VALUES (@Entry+1, @Entry+2); 72 | DELETE FROM `creature_questender` WHERE (`quest` = @Entry+2) AND (`id` IN (@Entry+1)); 73 | INSERT INTO `creature_questender` (`id`, `quest`) VALUES (@Entry+1, @Entry+2); 74 | 75 | -- Next = @Entry + 3 -------------------------------------------------------------------------------- /configurations/authserver.conf: -------------------------------------------------------------------------------- 1 | ############################################### 2 | # AzerothCore Auth Server configuration file # 3 | ############################################### 4 | [authserver] 5 | 6 | ################################################################################################### 7 | # SECTION INDEX 8 | # 9 | # EXAMPLE CONFIG 10 | # AUTH SERVER SETTINGS 11 | # MYSQL SETTINGS 12 | # CRYPTOGRAPHY 13 | # UPDATE SETTINGS 14 | # LOGGING SYSTEM SETTINGS 15 | # 16 | ################################################################################################### 17 | 18 | ################################################################################################### 19 | # EXAMPLE CONFIG 20 | # 21 | # Variable 22 | # Description: Brief description what the variable is doing. 23 | # Important: Annotation for important things about this variable. 24 | # Example: "Example, i.e. if the value is a string" 25 | # Default: 10 - (Enabled|Comment|Variable name in case of grouped config options) 26 | # 0 - (Disabled|Comment|Variable name in case of grouped config options) 27 | # 28 | # Note to developers: 29 | # - Copy this example to keep the formatting. 30 | # - Line breaks should be at column 100. 31 | ################################################################################################### 32 | 33 | ################################################################################################### 34 | # AUTH SERVER SETTINGS 35 | # 36 | # LogsDir 37 | # Description: Logs directory setting. 38 | # Important: LogsDir needs to be quoted, as the string might contain space characters. 39 | # Logs directory must exists, or log file creation will be disabled. 40 | # Example: "/home/youruser/azerothcore/logs" 41 | # Default: "" - (Log files will be stored in the current path) 42 | 43 | LogsDir = "" 44 | 45 | # 46 | # MaxPingTime 47 | # Description: Time (in minutes) between database pings. 48 | # Default: 30 49 | 50 | MaxPingTime = 30 51 | 52 | # 53 | # RealmServerPort 54 | # Description: TCP port to reach the auth server. 55 | # Default: 3724 56 | 57 | RealmServerPort = 3724 58 | 59 | # 60 | # 61 | # BindIP 62 | # Description: Bind auth server to IP/hostname 63 | # Default: "0.0.0.0" - (Bind to all IPs on the system) 64 | 65 | # 66 | # PidFile 67 | # Description: Auth server PID file. 68 | # Example: "./authserver.pid" - (Enabled) 69 | # Default: "" - (Disabled) 70 | 71 | PidFile = "" 72 | 73 | # 74 | # UseProcessors 75 | # Description: Processors mask for Windows and Linux based multi-processor systems. 76 | # Example: For a computer with 3 CPUs: 77 | # 1 - 1st CPU only 78 | # 2 - 2nd CPU only 79 | # 4 - 3rd CPU only 80 | # 6 - 2nd + 3rd CPUs, because "2 | 4" -> 6 81 | # Default: 0 - (Selected by OS) 82 | # 1+ - (Bit mask value of selected processors) 83 | 84 | UseProcessors = 0 85 | 86 | # 87 | # ProcessPriority 88 | # Description: Process priority setting for Windows and Linux based systems. 89 | # Details: On Linux, a nice value of -15 is used. (requires superuser). On Windows, process is set to HIGH class. 90 | # Default: 0 - (Normal) 91 | # 1 - (High) 92 | 93 | ProcessPriority = 0 94 | 95 | # 96 | # RealmsStateUpdateDelay 97 | # Description: Time (in seconds) between realm list updates. 98 | # Default: 20 - (Enabled) 99 | # 0 - (Disabled) 100 | 101 | RealmsStateUpdateDelay = 20 102 | 103 | # 104 | # WrongPass.MaxCount 105 | # Description: Number of login attempts with wrong password before the account or IP will be 106 | # banned. 107 | # Default: 0 - (Disabled) 108 | # 1+ - (Enabled) 109 | 110 | WrongPass.MaxCount = 0 111 | 112 | # 113 | # WrongPass.BanTime 114 | # Description: Time (in seconds) for banning account or IP for invalid login attempts. 115 | # Default: 600 - (10 minutes) 116 | # 0 - (Permanent ban) 117 | 118 | WrongPass.BanTime = 600 119 | 120 | # 121 | # WrongPass.BanType 122 | # Description: Ban type for invalid login attempts. 123 | # Default: 0 - (Ban IP) 124 | # 1 - (Ban Account) 125 | 126 | WrongPass.BanType = 0 127 | 128 | # 129 | # WrongPass.Logging 130 | # Description: Additionally log attempted wrong password logging 131 | # Default: 0 - (Disabled) 132 | # 1 - (Enabled) 133 | 134 | WrongPass.Logging = 0 135 | 136 | # 137 | # BanExpiryCheckInterval 138 | # Description: Time (in seconds) between checks for expired bans 139 | # Default: 60 140 | # 141 | 142 | BanExpiryCheckInterval = 60 143 | 144 | # 145 | # StrictVersionCheck 146 | # Description: Prevent modified clients from connecting 147 | # Default: 0 - (Disabled) 148 | # 1 - (Enabled) 149 | # 150 | 151 | StrictVersionCheck = 0 152 | 153 | # 154 | # SourceDirectory 155 | # Description: The path to your AzerothCore source directory. 156 | # If the path is left empty, the built-in CMAKE_SOURCE_DIR is used. 157 | # Example: "../AzerothCore" 158 | # Default: "" 159 | # 160 | 161 | SourceDirectory = "" 162 | 163 | # 164 | # MySQLExecutable 165 | # Description: The path to your MySQL CLI binary. 166 | # If the path is left empty, built-in path from cmake is used. 167 | # Example: "C:/Program Files/MariaDB 10.5/bin/mysql.exe" 168 | # "C:/Program Files/MySQL/MySQL Server 8.0/bin/mysql.exe" 169 | # "mysql.exe" 170 | # "/usr/bin/mysql" 171 | # Default: "" 172 | # 173 | 174 | MySQLExecutable = "" 175 | 176 | # 177 | # TempDir 178 | # Description: Temp directory setting. 179 | # Important: TempDir needs to be quoted, as the string might contain space characters. 180 | # TempDir directory must exists, or the server can't work properly 181 | # Example: "/home/youruser/azerothcore/temp" 182 | # Default: "" - (Temp files will be stored in the current path) 183 | 184 | TempDir = "" 185 | 186 | # 187 | # IPLocationFile 188 | # Description: The path to your IP2Location database CSV file. 189 | # Example: "C:/acore/IP2LOCATION-LITE-DB1.CSV" 190 | # "/home/acore/IP2LOCATION-LITE-DB1.CSV" 191 | # Default: "" - (Disabled) 192 | 193 | IPLocationFile = "" 194 | 195 | # 196 | # AllowLoggingIPAddressesInDatabase 197 | # Description: Specifies if IP addresses can be logged to the database 198 | # Default: 1 - (Enabled) 199 | # 0 - (Disabled) 200 | # 201 | 202 | AllowLoggingIPAddressesInDatabase = 1 203 | 204 | # 205 | ################################################################################################### 206 | 207 | ################################################################################################### 208 | # MYSQL SETTINGS 209 | # 210 | # LoginDatabaseInfo 211 | # Description: Database connection settings for the realm server. 212 | # Example: "hostname;port;username;password;database" 213 | # ".;somenumber;username;password;database" - (Use named pipes on Windows 214 | # "enable-named-pipe" to [mysqld] 215 | # section my.ini) 216 | # ".;/path/to/unix_socket;username;password;database" - (use Unix sockets on 217 | # Unix/Linux) 218 | # Default: "127.0.0.1;3306;acore;acore;acore_auth" 219 | 220 | # LoginDatabaseInfo = "127.0.0.1;3306;acore;acore;acore_auth" 221 | 222 | # 223 | # Database.Reconnect.Seconds 224 | # Database.Reconnect.Attempts 225 | # 226 | # Description: How many seconds between every reconnection attempt 227 | # and how many attempts will be performed in total 228 | # Default: 20 attempts every 15 seconds 229 | # 230 | 231 | Database.Reconnect.Seconds = 15 232 | Database.Reconnect.Attempts = 20 233 | 234 | # 235 | # LoginDatabase.WorkerThreads 236 | # Description: The amount of worker threads spawned to handle asynchronous (delayed) MySQL 237 | # statements. Each worker thread is mirrored with its own connection to the 238 | # Default: 1 239 | 240 | LoginDatabase.WorkerThreads = 1 241 | 242 | # 243 | # LoginDatabase.SynchThreads 244 | # Description: The amount of MySQL connections spawned to handle. 245 | # Default: 1 - (LoginDatabase.WorkerThreads) 246 | # 247 | 248 | LoginDatabase.SynchThreads = 1 249 | 250 | # 251 | ################################################################################################### 252 | 253 | ################################################################################################### 254 | # CRYPTOGRAPHY 255 | 256 | # 257 | # EnableTOTP 258 | # Description: Check if a TOTP token is needed on account login 259 | # 260 | # Default: 0 - (Disabled) 261 | # 1 - (Enabled) 262 | 263 | EnableTOTP = 0 264 | 265 | # TOTPMasterSecret 266 | # Description: The master key used to encrypt TOTP secrets for database storage. 267 | # If you want to change this, uncomment TOTPOldMasterSecret, then copy 268 | # your old secret there and startup authserver once. Afterwards, you can re- 269 | # comment that line and get rid of your old secret. 270 | # 271 | # Default: - (Store TOTP secrets unencrypted) 272 | # Example: 000102030405060708090A0B0C0D0E0F 273 | 274 | TOTPMasterSecret = 275 | # TOTPOldMasterSecret = 276 | 277 | # 278 | ################################################################################################### 279 | 280 | ################################################################################################### 281 | # UPDATE SETTINGS 282 | # 283 | # Updates.EnableDatabases 284 | # Description: A mask that describes which databases shall be updated. 285 | # 286 | # Following flags are available 287 | # DATABASE_LOGIN = 1, // Auth database 288 | # 289 | # Default: 0 - (All Disabled) 290 | # 1 - (All Enabled) 291 | 292 | Updates.EnableDatabases = 1 293 | 294 | # 295 | # Updates.AutoSetup 296 | # Description: Auto populate empty databases. 297 | # Default: 1 - (Enabled) 298 | # 0 - (Disabled) 299 | 300 | Updates.AutoSetup = 1 301 | 302 | # 303 | # Updates.Redundancy 304 | # Description: Perform data redundancy checks through hashing 305 | # to detect changes on sql updates and reapply it. 306 | # Default: 1 - (Enabled) 307 | # 0 - (Disabled) 308 | 309 | Updates.Redundancy = 1 310 | 311 | # 312 | # Updates.ArchivedRedundancy 313 | # Description: Check hashes of archived updates (slows down startup). 314 | # Default: 0 - (Disabled) 315 | # 1 - (Enabled) 316 | 317 | Updates.ArchivedRedundancy = 0 318 | 319 | # 320 | # Updates.AllowRehash 321 | # Description: Inserts the current file hash in the database if it is left empty. 322 | # Useful if you want to mark a file as applied but you don't know its hash. 323 | # Default: 1 - (Enabled) 324 | # 0 - (Disabled) 325 | 326 | Updates.AllowRehash = 1 327 | 328 | # 329 | # Updates.CleanDeadRefMaxCount 330 | # Description: Cleans dead/ orphaned references that occur if an update was removed or renamed and edited in one step. 331 | # It only starts the clean up if the count of the missing updates is below or equal the Updates.CleanDeadRefMaxCount value. 332 | # This way prevents erasing of the update history due to wrong source directory state (maybe wrong branch or bad revision). 333 | # Disable this if you want to know if the database is in a possible "dirty state". 334 | # Default: 3 - (Enabled) 335 | # 0 - (Disabled) 336 | # -1 - (Enabled - unlimited) 337 | 338 | Updates.CleanDeadRefMaxCount = 3 339 | ################################################################################################### 340 | 341 | ################################################################################################### 342 | # 343 | # LOGGING SYSTEM SETTINGS 344 | # 345 | # Appender config values: Given an appender "name" 346 | # Appender.name 347 | # Description: Defines 'where to log' 348 | # Format: Type,LogLevel,Flags,optional1,optional2,optional3 349 | # 350 | # Type 351 | # 0 - (None) 352 | # 1 - (Console) 353 | # 2 - (File) 354 | # 3 - (DB) 355 | # 356 | # LogLevel 357 | # 0 - (Disabled) 358 | # 1 - (Fatal) 359 | # 2 - (Error) 360 | # 3 - (Warning) 361 | # 4 - (Info) 362 | # 5 - (Debug) 363 | # 6 - (Trace) 364 | # 365 | # Flags: 366 | # 0 - None 367 | # 1 - Prefix Timestamp to the text 368 | # 2 - Prefix Log Level to the text 369 | # 4 - Prefix Log Filter type to the text 370 | # 8 - Append timestamp to the log file name. Format: YYYY-MM-DD_HH-MM-SS (Only used with Type = 2) 371 | # 16 - Make a backup of existing file before overwrite (Only used with Mode = w) 372 | # 373 | # Colors (read as optional1 if Type = Console) 374 | # Format: "fatal error warn info debug trace" 375 | # 0 - BLACK 376 | # 1 - RED 377 | # 2 - GREEN 378 | # 3 - BROWN 379 | # 4 - BLUE 380 | # 5 - MAGENTA 381 | # 6 - CYAN 382 | # 7 - GREY 383 | # 8 - YELLOW 384 | # 9 - LRED 385 | # 10 - LGREEN 386 | # 11 - LBLUE 387 | # 12 - LMAGENTA 388 | # 13 - LCYAN 389 | # 14 - WHITE 390 | # Example: "1 9 3 6 5 8" 391 | # 392 | # File: Name of the file (read as optional1 if Type = File) 393 | # Allows to use one "%s" to create dynamic files 394 | # 395 | # Mode: Mode to open the file (read as optional2 if Type = File) 396 | # a - (Append) 397 | # w - (Overwrite) 398 | # 399 | # MaxFileSize: Maximum file size of the log file before creating a new log file 400 | # (read as optional3 if Type = File) 401 | # Size is measured in bytes expressed in a 64-bit unsigned integer. 402 | # Maximum value is 4294967295 (4 GB). Leave blank for no limit. 403 | # NOTE: Does not work with dynamic filenames. 404 | # Example: 536870912 (512 MB) 405 | # 406 | 407 | Appender.Console=1,5,0,"1 9 3 6 5 8" 408 | Appender.Auth=2,5,0,Auth.log,w 409 | 410 | # Logger config values: Given a logger "name" 411 | # Logger.name 412 | # Description: Defines 'What to log' 413 | # Format: LogLevel,AppenderList 414 | # 415 | # LogLevel 416 | # 0 - (Disabled) 417 | # 1 - (Fatal) 418 | # 2 - (Error) 419 | # 3 - (Warning) 420 | # 4 - (Info) 421 | # 5 - (Debug) 422 | # 6 - (Trace) 423 | # 424 | # AppenderList: List of appenders linked to logger 425 | # (Using spaces as separator). 426 | # 427 | 428 | Logger.root=4,Console Auth 429 | 430 | # 431 | ################################################################################################### 432 | 433 | # Dynamically populated values: 434 | 435 | -------------------------------------------------------------------------------- /sql/world/a-03-better-herb-spawns.sql: -------------------------------------------------------------------------------- 1 | 2 | -- Better Herb Node Spawn NUMBERS (not rates!) 3 | 4 | -- Structure 5 | -- gameobject_template.entry -> gameobject.id -> gameobject.guid -> pool_gameobject.guid; 6 | 7 | -- For debugging... 8 | -- SELECT entry,name FROM gameobject_template WHERE entry IN (1617,1618,1619,1620,1621,1622,1624,2041,2042,2044,2045,2046,2866,3724,3725,3726,3727,3729,3730,6584,6587,6588,6636,6637,6639,6641,0164,0168,1270,1275,1277,1279,1282,3043,3044,3046,9973); 9 | -- +-------+--------------------------+ 10 | -- | entry | name | 11 | -- +-------+--------------------------+ 12 | -- | 1617 | Silverleaf | 13 | -- | 1618 | Peacebloom | 14 | -- | 1619 | Earthroot | 15 | -- | 1620 | Mageroyal | 16 | -- | 1621 | Briarthorn | 17 | -- | 1622 | Bruiseweed | 18 | -- | 1624 | Kingsblood | 19 | -- | 2041 | Liferoot | 20 | -- | 2042 | Fadeleaf | 21 | -- | 2044 | Wintersbite | 22 | -- | 2045 | Stranglekelp | 23 | -- | 2046 | Goldthorn | 24 | -- | 2866 | Firebloom | 25 | -- | 3724 | Peacebloom | 26 | -- | 3725 | Silverleaf | 27 | -- | 3726 | Earthroot | 28 | -- | 3727 | Mageroyal | 29 | -- | 3729 | Briarthorn | 30 | -- | 3730 | Bruiseweed | 31 | -- +-------+--------------------------+ 32 | 33 | -- Current values as of 2023-09-24: 34 | -- +-------+-----------+-----------------------------------------------------------+ 35 | -- | entry | max_limit | description | 36 | -- +-------+-----------+-----------------------------------------------------------+ 37 | -- | 951 | 80 | MASTER Herbs Westfall zone 40 | 38 | -- | 961 | 85 | MASTER Herbs Darkshore zone 148 | 39 | -- | 801 | 60 | Master Zone 17 Area 17 (60 out of 305 nodes | 40 | -- | 800 | 18 | Master Zone 17 Leftover Areas (18 out of 88 nodes) | 41 | -- | 809 | 10 | Master Zone 17 Area 1156 (18 out of 92 nodes | 42 | -- | 802 | 8 | Master Zone 17 Area 383 (8 out of 41 nodes | 43 | -- | 956 | 60 | MASTER Herbs Silverpine Forest zone 130 | 44 | -- | 952 | 55 | MASTER Herbs Loch Modan zone 38 | 45 | -- | 804 | 3 | Master Zone 17 Area 386 (3 out of 15 nodes | 46 | -- | 811 | 10 | Master Zone 17 Area 1699 (4 out of 21 nodes | 47 | -- | 805 | 10 | Master Zone 17 Area 387 (10 out of 54 nodes | 48 | -- | 806 | 4 | Master Zone 17 Area 388 (4 out of 21 nodes | 49 | -- | 718 | 25 | Silverleaf in Eversong Woods | 50 | -- | 734 | 22 | Silverleaf in Ghostlands | 51 | -- | 729 | 23 | Silverleaf in Azuremyst Isle | 52 | -- | 732 | 2 | Silverleaf in Silvermyst Isle | 53 | -- | 717 | 25 | Peacebloom in Eversong Woods | 54 | -- | 728 | 23 | Peacebloom in Azuremyst Isle | 55 | -- | 731 | 2 | Peacebloom in Silvermyst Isle | 56 | -- | 950 | 55 | MASTER Herbs Redridge Mountains zone 44 | 57 | -- | 812 | 10 | Master Zone 17 Area 1700 (6 out of 28 nodes | 58 | -- | 807 | 8 | Master Zone 17 Area 390 (8 out of 39 nodes | 59 | -- | 808 | 17 | Master Zone 17 Area 391 (17 out of 86 nodes | 60 | -- | 813 | 10 | Master Zone 17 Area 1701 (8 out of 39 nodes | 61 | -- | 719 | 15 | Earthroot in Eversong Woods | 62 | -- | 730 | 12 | Earthroot in Azuremyst Isle | 63 | -- | 733 | 3 | Earthroot in Silvermyst Isle | 64 | -- | 810 | 10 | Master Zone 17 Area 1698 (4 out of 20 nodes | 65 | -- | 803 | 4 | Master Zone 17 Area 385 (4 out of 19 nodes | 66 | -- | 995 | 80 | MASTER Herbs Duskwood zone 10 | 67 | -- | 949 | 75 | MASTER Herbs Stonetalon Mountains zone 406 | 68 | -- | 994 | 90 | MASTER Herbs Wetlands zone 11 | 69 | -- | 960 | 95 | MASTER Herbs Ashenvale zone 331 | 70 | -- | 958 | 70 | MASTER Herbs Hillsbrad Foothills zone 267 | 71 | -- | 962 | 35 | MASTER Herbs Thousand Needles zone 400 | 72 | -- | 825 | 5 | Master Herbs Zone 405 Leftover Areas (5 out of 27 nodes) | 73 | -- | 826 | 5 | Master Herbs Zone 405 Leftover Areas (5 out of 22 nodes) | 74 | -- | 959 | 85 | MASTER Herbs Arathi Highlands zone 45 | 75 | -- | 821 | 10 | Master Herbs Zone 405 Leftover Areas (10 out of 41 nodes) | 76 | -- | 564 | 8 | Bruiseweed in Alterac Mountains | 77 | -- | 822 | 8 | Master Herbs Zone 405 Leftover Areas (8 out of 40 nodes) | 78 | -- | 565 | 2 | Kingsblood in Alterac Mountains | 79 | -- | 996 | 85 | MASTER Herbs Swamp of Sorrows zone 8 | 80 | -- | 988 | 100 | MASTER Herbs Stranglethorn Vale zone 33 | 81 | -- | 998 | 45 | MASTER Herbs Badlands zone 3 | 82 | -- | 824 | 5 | Master Herbs Zone 405 Leftover Areas (5 out of 20 nodes) | 83 | -- | 947 | 15 | MASTER Herbs Searing Gorge zone 51 | 84 | -- | 571 | 8 | Liferoot in Alterac Mountains | 85 | -- | 964 | 65 | MASTER Herbs Feralas zone 357 | 86 | -- | 965 | 90 | MASTER Herbs Hinterlands zone 47 | 87 | -- | 8253 | 1 | Netherstorm - Eco-Dome Midrealm - Liferoot | 88 | -- | 8249 | 1 | Netherstorm - Eco-Dome Sutheron - Liferoot | 89 | -- | 572 | 11 | Fadeleaf in Alterac Mountains | 90 | -- | 570 | 9 | Wintersbite in Alterac Mountains | 91 | -- | 573 | 1 | Stranglekelp in Alterac Mountains | 92 | -- | 990 | 85 | MASTER Herbs Azshara zone 16 | 93 | -- | 566 | 12 | Goldthorn in Alterac Mountains | 94 | -- | 991 | 25 | MASTER Herbs Dustwallow Marsh zone 15 | 95 | -- | 418 | 4 | Teldrassil Peacebloom Pool 3 of 5--4 spawns active | 96 | -- | 420 | 7 | Teldrassil Peacebloom Pool 5 of 5--7 spawns active | 97 | -- | 416 | 9 | Teldrassil Peacebloom Pool 1 of 5--9 spawns active | 98 | -- | 419 | 6 | Teldrassil Peacebloom Pool 4 of 5--6 spawns active | 99 | -- | 417 | 4 | Teldrassil Peacebloom Pool 2 of 5--4 spawns active | 100 | -- | 423 | 2 | Teldrassil Mageroyal Pool 3 of 3--2 spawns active | 101 | -- | 421 | 2 | Teldrassil Mageroyal Pool 1 of 3--2 spawns active | 102 | -- | 422 | 2 | Teldrassil Mageroyal Pool 2 of 3--2 spawns active | 103 | -- | 428 | 7 | Teldrassil Silverleaf Pool 5 of 5--7 spawns active | 104 | -- | 426 | 5 | Teldrassil Silverleaf Pool 3 of 5--5 spawns active | 105 | -- | 424 | 10 | Teldrassil Silverleaf Pool 1 of 5--10 spawns active | 106 | -- | 427 | 6 | Teldrassil Silverleaf Pool 4 of 5--6 spawns active | 107 | -- | 425 | 8 | Teldrassil Silverleaf Pool 2 of 5--8 spawns active | 108 | -- | 431 | 3 | Teldrassil Earthroot Pool 3 of 4--3 spawns active | 109 | -- | 429 | 9 | Teldrassil Earthroot Pool 1 of 4--9 spawns active | 110 | -- | 432 | 4 | Teldrassil Earthroot Pool 4 of 4--4 spawns active | 111 | -- | 430 | 4 | Teldrassil Earthroot Pool 2 of 4--4 spawns active | 112 | -- | 997 | 30 | MASTER Herbs Blasted Lands zone 4 | 113 | -- | 963 | 35 | MASTER Herbs Tanaris zone 440 | 114 | -- | 736 | 11 | Earthroot in Ghostlands | 115 | -- | 737 | 8 | Mageroyal in Ghostlands | 116 | -- | 738 | 8 | Briarthorn in Ghostlands | 117 | -- | 735 | 14 | Peacebloom in Ghostlands | 118 | -- | 740 | 6 | Bruiseweed in Ghostlands | 119 | -- | 739 | 6 | Stranglekelp in Ghostlands | 120 | -- | 500 | 25 | Silverleaf in Durotar | 121 | -- | 491 | 25 | Silverleaf in Tirisfal | 122 | -- | 504 | 25 | Silverleaf in Mulgore | 123 | -- | 494 | 75 | Silverleaf in Elwynn Forest | 124 | -- | 497 | 25 | Silverleaf in Dun Morogh | 125 | -- | 489 | 15 | Earthroot in Tirisfal | 126 | -- | 495 | 15 | Earthroot in Dun Morogh | 127 | -- | 496 | 25 | Peacebloom in Dun Morogh | 128 | -- | 498 | 25 | Peacebloom in Durotar | 129 | -- | 493 | 25 | Peacebloom in Elwynn Forest | 130 | -- | 503 | 25 | Peacebloom in Mulgore | 131 | -- | 490 | 25 | Peacebloom in Tirisfal | 132 | -- | 502 | 15 | Earthroot in Mulgore | 133 | -- | 492 | 15 | Earthroot in Elwynn Forest | 134 | -- | 499 | 15 | Earthroot in Durotar | 135 | -- | 501 | 4 | Mageroyal in Durotar | 136 | -- | 745 | 9 | Briarthorn in Bloodmyst Isle | 137 | -- | 742 | 16 | Peacebloom in Bloodmyst Isle | 138 | -- | 741 | 22 | Silverleaf in Bloodmyst Isle | 139 | -- | 747 | 8 | Stranglekelp in Bloodmyst Isle | 140 | -- | 746 | 5 | Bruiseweed in Bloodmyst Isle | 141 | -- | 823 | 4 | Master Herbs Zone 405 Leftover Areas (4 out of 18 nodes) | 142 | -- | 743 | 12 | Earthroot in Bloodmyst Isle | 143 | -- | 744 | 8 | Mageroyal in Bloodmyst Isle | 144 | -- | 748 | 2 | Peacebloom in Wyrmscar Isle | 145 | -- | 750 | 1 | Mageroyal in Wyrmscar Isle | 146 | -- | 749 | 2 | Silverleaf in Wyrmscar Isle | 147 | -- | 751 | 1 | Bruiseweed in Wyrmscar Isle | 148 | -- +-------+-----------+-----------------------------------------------------------+ 149 | -- 111 rows in set (0.110 sec) 150 | 151 | -- Setting them to defaults, so this entire SQL file becomes idempotent 152 | UPDATE acore_world.pool_template SET max_limit= 80 WHERE entry=951; 153 | UPDATE acore_world.pool_template SET max_limit= 85 WHERE entry=961; 154 | UPDATE acore_world.pool_template SET max_limit= 60 WHERE entry=801; 155 | UPDATE acore_world.pool_template SET max_limit= 18 WHERE entry=800; 156 | UPDATE acore_world.pool_template SET max_limit= 10 WHERE entry=809; 157 | UPDATE acore_world.pool_template SET max_limit= 8 WHERE entry=802; 158 | UPDATE acore_world.pool_template SET max_limit= 60 WHERE entry=956; 159 | UPDATE acore_world.pool_template SET max_limit= 55 WHERE entry=952; 160 | UPDATE acore_world.pool_template SET max_limit= 3 WHERE entry=804; 161 | UPDATE acore_world.pool_template SET max_limit= 10 WHERE entry=811; 162 | UPDATE acore_world.pool_template SET max_limit= 10 WHERE entry=805; 163 | UPDATE acore_world.pool_template SET max_limit= 4 WHERE entry=806; 164 | UPDATE acore_world.pool_template SET max_limit= 25 WHERE entry=718; 165 | UPDATE acore_world.pool_template SET max_limit= 22 WHERE entry=734; 166 | UPDATE acore_world.pool_template SET max_limit= 23 WHERE entry=729; 167 | UPDATE acore_world.pool_template SET max_limit= 2 WHERE entry=732; 168 | UPDATE acore_world.pool_template SET max_limit= 25 WHERE entry=717; 169 | UPDATE acore_world.pool_template SET max_limit= 23 WHERE entry=728; 170 | UPDATE acore_world.pool_template SET max_limit= 2 WHERE entry=731; 171 | UPDATE acore_world.pool_template SET max_limit= 55 WHERE entry=950; 172 | UPDATE acore_world.pool_template SET max_limit= 10 WHERE entry=812; 173 | UPDATE acore_world.pool_template SET max_limit= 8 WHERE entry=807; 174 | UPDATE acore_world.pool_template SET max_limit= 17 WHERE entry=808; 175 | UPDATE acore_world.pool_template SET max_limit= 10 WHERE entry=813; 176 | UPDATE acore_world.pool_template SET max_limit= 15 WHERE entry=719; 177 | UPDATE acore_world.pool_template SET max_limit= 12 WHERE entry=730; 178 | UPDATE acore_world.pool_template SET max_limit= 3 WHERE entry=733; 179 | UPDATE acore_world.pool_template SET max_limit= 10 WHERE entry=810; 180 | UPDATE acore_world.pool_template SET max_limit= 4 WHERE entry=803; 181 | UPDATE acore_world.pool_template SET max_limit= 80 WHERE entry=995; 182 | UPDATE acore_world.pool_template SET max_limit= 75 WHERE entry=949; 183 | UPDATE acore_world.pool_template SET max_limit= 90 WHERE entry=994; 184 | UPDATE acore_world.pool_template SET max_limit= 95 WHERE entry=960; 185 | UPDATE acore_world.pool_template SET max_limit= 70 WHERE entry=958; 186 | UPDATE acore_world.pool_template SET max_limit= 35 WHERE entry=962; 187 | UPDATE acore_world.pool_template SET max_limit= 5 WHERE entry=825; 188 | UPDATE acore_world.pool_template SET max_limit= 5 WHERE entry=826; 189 | UPDATE acore_world.pool_template SET max_limit= 85 WHERE entry=959; 190 | UPDATE acore_world.pool_template SET max_limit= 10 WHERE entry=821; 191 | UPDATE acore_world.pool_template SET max_limit= 8 WHERE entry=564; 192 | UPDATE acore_world.pool_template SET max_limit= 8 WHERE entry=822; 193 | UPDATE acore_world.pool_template SET max_limit= 2 WHERE entry=565; 194 | UPDATE acore_world.pool_template SET max_limit= 85 WHERE entry=996; 195 | UPDATE acore_world.pool_template SET max_limit=100 WHERE entry=988; 196 | UPDATE acore_world.pool_template SET max_limit= 45 WHERE entry=998; 197 | UPDATE acore_world.pool_template SET max_limit= 5 WHERE entry=824; 198 | UPDATE acore_world.pool_template SET max_limit= 15 WHERE entry=947; 199 | UPDATE acore_world.pool_template SET max_limit= 8 WHERE entry=571; 200 | UPDATE acore_world.pool_template SET max_limit= 65 WHERE entry=964; 201 | UPDATE acore_world.pool_template SET max_limit= 90 WHERE entry=965; 202 | UPDATE acore_world.pool_template SET max_limit= 1 WHERE entry=8253; 203 | UPDATE acore_world.pool_template SET max_limit= 1 WHERE entry=8249; 204 | UPDATE acore_world.pool_template SET max_limit= 11 WHERE entry=572; 205 | UPDATE acore_world.pool_template SET max_limit= 9 WHERE entry=570; 206 | UPDATE acore_world.pool_template SET max_limit= 1 WHERE entry=573; 207 | UPDATE acore_world.pool_template SET max_limit= 85 WHERE entry=990; 208 | UPDATE acore_world.pool_template SET max_limit= 12 WHERE entry=566; 209 | UPDATE acore_world.pool_template SET max_limit= 25 WHERE entry=991; 210 | UPDATE acore_world.pool_template SET max_limit= 4 WHERE entry=418; 211 | UPDATE acore_world.pool_template SET max_limit= 7 WHERE entry=420; 212 | UPDATE acore_world.pool_template SET max_limit= 9 WHERE entry=416; 213 | UPDATE acore_world.pool_template SET max_limit= 6 WHERE entry=419; 214 | UPDATE acore_world.pool_template SET max_limit= 4 WHERE entry=417; 215 | UPDATE acore_world.pool_template SET max_limit= 2 WHERE entry=423; 216 | UPDATE acore_world.pool_template SET max_limit= 2 WHERE entry=421; 217 | UPDATE acore_world.pool_template SET max_limit= 2 WHERE entry=422; 218 | UPDATE acore_world.pool_template SET max_limit= 7 WHERE entry=428; 219 | UPDATE acore_world.pool_template SET max_limit= 5 WHERE entry=426; 220 | UPDATE acore_world.pool_template SET max_limit= 10 WHERE entry=424; 221 | UPDATE acore_world.pool_template SET max_limit= 6 WHERE entry=427; 222 | UPDATE acore_world.pool_template SET max_limit= 8 WHERE entry=425; 223 | UPDATE acore_world.pool_template SET max_limit= 3 WHERE entry=431; 224 | UPDATE acore_world.pool_template SET max_limit= 9 WHERE entry=429; 225 | UPDATE acore_world.pool_template SET max_limit= 4 WHERE entry=432; 226 | UPDATE acore_world.pool_template SET max_limit= 4 WHERE entry=430; 227 | UPDATE acore_world.pool_template SET max_limit= 30 WHERE entry=997; 228 | UPDATE acore_world.pool_template SET max_limit= 35 WHERE entry=963; 229 | UPDATE acore_world.pool_template SET max_limit= 11 WHERE entry=736; 230 | UPDATE acore_world.pool_template SET max_limit= 8 WHERE entry=737; 231 | UPDATE acore_world.pool_template SET max_limit= 8 WHERE entry=738; 232 | UPDATE acore_world.pool_template SET max_limit= 14 WHERE entry=735; 233 | UPDATE acore_world.pool_template SET max_limit= 6 WHERE entry=740; 234 | UPDATE acore_world.pool_template SET max_limit= 6 WHERE entry=739; 235 | UPDATE acore_world.pool_template SET max_limit= 25 WHERE entry=500; 236 | UPDATE acore_world.pool_template SET max_limit= 25 WHERE entry=491; 237 | UPDATE acore_world.pool_template SET max_limit= 25 WHERE entry=504; 238 | UPDATE acore_world.pool_template SET max_limit= 75 WHERE entry=494; 239 | UPDATE acore_world.pool_template SET max_limit= 25 WHERE entry=497; 240 | UPDATE acore_world.pool_template SET max_limit= 15 WHERE entry=489; 241 | UPDATE acore_world.pool_template SET max_limit= 15 WHERE entry=495; 242 | UPDATE acore_world.pool_template SET max_limit= 25 WHERE entry=496; 243 | UPDATE acore_world.pool_template SET max_limit= 25 WHERE entry=498; 244 | UPDATE acore_world.pool_template SET max_limit= 25 WHERE entry=493; 245 | UPDATE acore_world.pool_template SET max_limit= 25 WHERE entry=503; 246 | UPDATE acore_world.pool_template SET max_limit= 25 WHERE entry=490; 247 | UPDATE acore_world.pool_template SET max_limit= 15 WHERE entry=502; 248 | UPDATE acore_world.pool_template SET max_limit= 15 WHERE entry=492; 249 | UPDATE acore_world.pool_template SET max_limit= 15 WHERE entry=499; 250 | UPDATE acore_world.pool_template SET max_limit= 4 WHERE entry=501; 251 | UPDATE acore_world.pool_template SET max_limit= 9 WHERE entry=745; 252 | UPDATE acore_world.pool_template SET max_limit= 16 WHERE entry=742; 253 | UPDATE acore_world.pool_template SET max_limit= 22 WHERE entry=741; 254 | UPDATE acore_world.pool_template SET max_limit= 8 WHERE entry=747; 255 | UPDATE acore_world.pool_template SET max_limit= 5 WHERE entry=746; 256 | UPDATE acore_world.pool_template SET max_limit= 4 WHERE entry=823; 257 | UPDATE acore_world.pool_template SET max_limit= 12 WHERE entry=743; 258 | UPDATE acore_world.pool_template SET max_limit= 8 WHERE entry=744; 259 | UPDATE acore_world.pool_template SET max_limit= 2 WHERE entry=748; 260 | UPDATE acore_world.pool_template SET max_limit= 1 WHERE entry=750; 261 | UPDATE acore_world.pool_template SET max_limit= 2 WHERE entry=749; 262 | UPDATE acore_world.pool_template SET max_limit= 1 WHERE entry=751; 263 | 264 | SET @HerbMaxLimitMultiplier = 6; 265 | 266 | SET -- Herb IDs 267 | 268 | -- SELECT entry, name FROM gameobject_template WHERE name like '%Silverleaf%'; 269 | @Silverleaf = 1617, 270 | @Silverleaf2 = 3725, 271 | 272 | -- SELECT entry, name FROM gameobject_template WHERE name like '%Peacebloom%'; 273 | @Peacebloom = 1618, 274 | @Peacebloom2 = 3724, 275 | 276 | -- SELECT entry, name FROM gameobject_template WHERE name like '%Earthroot%'; 277 | @Earthroot = 1619, 278 | @Earthroot2 = 3726, 279 | 280 | -- SELECT entry, name FROM gameobject_template WHERE name like '%Mageroyal%'; 281 | @Mageroyal = 1620, 282 | @Mageroyal2 = 3727, 283 | 284 | -- SELECT entry, name FROM gameobject_template WHERE name like '%Briarthorn%'; 285 | @Briarthorn = 1621, 286 | @Briarthorn2 = 3729, 287 | 288 | -- SELECT entry, name FROM gameobject_template WHERE name like '%Bruiseweed%'; 289 | @Bruiseweed = 1622, 290 | @Bruiseweed2 = 3730, 291 | 292 | -- SELECT entry, name FROM gameobject_template WHERE name like '%Kingsblood%'; 293 | @Kingsblood = 1624, 294 | 295 | -- SELECT entry, name FROM gameobject_template WHERE name like '%Liferoot%'; 296 | @Liferoot = 2041, 297 | 298 | -- SELECT entry, name FROM gameobject_template WHERE name like '%Fadeleaf%'; 299 | @Fadeleaf = 2042, 300 | 301 | -- SELECT entry, name FROM gameobject_template WHERE name like '%Wintersbite%'; 302 | @Wintersbite = 2044, 303 | 304 | -- SELECT entry, name FROM gameobject_template WHERE name like '%Stranglekelp%'; 305 | @Stranglekelp = 2045, 306 | 307 | -- SELECT entry, name FROM gameobject_template WHERE name like '%Goldthorn%'; 308 | @Goldthorn = 2046, 309 | 310 | -- SELECT entry, name FROM gameobject_template WHERE name like '%Firebloom%'; 311 | @Firebloom = 2866; 312 | 313 | -- Lookup current values: 314 | -- SELECT DISTINCT pt.* FROM pool_template pt 315 | -- INNER JOIN gameobject g ON g.id IN ( 316 | -- @Silverleaf, 317 | -- @Silverleaf2, 318 | -- @Peacebloom, 319 | -- @Peacebloom2, 320 | -- @Earthroot, 321 | -- @Earthroot2, 322 | -- @Mageroyal, 323 | -- @Mageroyal2, 324 | -- @Briarthorn, 325 | -- @Briarthorn2, 326 | -- @Bruiseweed, 327 | -- @Bruiseweed2, 328 | -- @Kingsblood, 329 | -- @Liferoot, 330 | -- @Fadeleaf, 331 | -- @Wintersbite, 332 | -- @Stranglekelp, 333 | -- @Goldthorn, 334 | -- @Firebloom 335 | -- ) 336 | -- INNER JOIN pool_gameobject pgo ON pgo.guid=g.guid 337 | -- WHERE pt.entry=pgo.pool_entry; 338 | 339 | UPDATE acore_world.pool_template 340 | INNER JOIN (SELECT pt.* FROM acore_world.pool_template pt 341 | INNER JOIN acore_world.gameobject g ON g.id IN ( 342 | @Silverleaf, 343 | @Silverleaf2, 344 | @Peacebloom, 345 | @Peacebloom2, 346 | @Earthroot, 347 | @Earthroot2, 348 | @Mageroyal, 349 | @Mageroyal2, 350 | @Briarthorn, 351 | @Briarthorn2, 352 | @Bruiseweed, 353 | @Bruiseweed2, 354 | @Kingsblood, 355 | @Liferoot, 356 | @Fadeleaf, 357 | @Wintersbite, 358 | @Stranglekelp, 359 | @Goldthorn, 360 | @Firebloom 361 | ) 362 | INNER JOIN acore_world.pool_gameobject pgo ON pgo.guid=g.guid 363 | WHERE pt.entry=pgo.pool_entry) as objects 364 | ON acore_world.pool_template.entry = objects.entry 365 | SET acore_world.pool_template.max_limit=(acore_world.pool_template.max_limit * @HerbMaxLimitMultiplier); 366 | --------------------------------------------------------------------------------